Ответ 1
Сделайте сначала select
clients.select{|c| c.type == 'tablet'}.map(&:ip)
У меня есть такая структура:
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
?
Сделайте сначала select
clients.select{|c| c.type == 'tablet'}.map(&:ip)
Ответ прост:
clients.map { |client| client.ip if client.type == 'tablet' }.compact
Сопоставление с условием даст нильс для клиентов, которые не выполнили условие, поскольку только мы сохранили compact
, которая фактически сбросит значения nil.
Альтернативный метод Серхио Туленцева с использованием #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)
Рубин 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]
Здесь хорошо читать на эту тему.
Надеюсь, что кому-то пригодится!