"карта" на основе условия

У меня есть такая структура:

Struct.new("Test", :loc, :type, :hostname, :ip)

clients = [
Struct::TestClient.new(1, :pc, "pc1", "192.168.0.1")
Struct::TestClient.new(1, :pc, "pc2", "192.168.0.2")
Struct::TestClient.new(1, :tablet, "tablet1", "192.168.0.3")
Struct::TestClient.new(1, :tablet, "tablet2", "192.168.0.3")
and etc...
]

Если я хочу получить IP-адрес всех устройств, я могу использовать test_clients.map(&:ip). Как выбрать IP-адреса определенных устройств, скажем, всех типов устройств, называемых "tablet"? Как я могу сделать это с помощью map?

Ответ 1

Сделайте сначала select

clients.select{|c| c.type == 'tablet'}.map(&:ip)

Ответ 2

Ответ прост:

clients.map { |client| client.ip if client.type == 'tablet' }.compact

Сопоставление с условием даст нильс для клиентов, которые не выполнили условие, поскольку только мы сохранили compact, которая фактически сбросит значения nil.

Ответ 3

Альтернативный метод Серхио Туленцева с использованием #collect. Я думаю, что использование #collect здесь семантически корректно. Я знаю, что ОП спросил, как использовать #map, но это мои два цента.

clients.collect { |c| c.ip if c.type == "tablet" } # will return nils for clients where the type is not "tablet"

# or

clients.select { |c| c.type == "tablet" }.collect(&ip)

Ответ 4

Рубин 2. 7+

Ruby 2.7 представляет filter_map для этой цели. Это идиоматично и производительно, и я ожидаю, что это станет нормой очень скоро.

Например:

numbers = [1, 2, 5, 8, 10, 13]
enum.filter_map { |i| i * 2 if i.even? }
# => [4, 16, 20]

Здесь хорошо читать на эту тему.

Надеюсь, что кому-то пригодится!