`map` based on condition
Solution 1
Do a select
first
clients.select{|c| c.type == 'tablet'}.map(&:ip)
Solution 2
Ruby 2.7+
Ruby 2.7 is introducing filter_map
for this exact purpose. It's idiomatic and performant, and I'd expect it to become the norm very soon.
For example:
numbers = [1, 2, 5, 8, 10, 13]
enum.filter_map { |i| i * 2 if i.even? }
# => [4, 16, 20]
Here's a good read on the subject.
Hope that's useful to someone!
Solution 3
Answer is as simple as that:
clients.map { |client| client.ip if client.type == 'tablet' }.compact
Mapping with condition will give nils for clients which failed the condition, for that only we kept compact
, which will actually flush the nil values.
Solution 4
An alternate to Sergio Tulentsev's method using #collect
. I think using #collect
is semantically correct here. I know the O.P. asked how to use #map
, but it's my two cents.
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)
sylvian
Updated on June 13, 2020Comments
-
sylvian about 4 years
I have a struct like this:
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... ]
If I want to get the IP address of all devices, I can use
test_clients.map(&:ip)
. How do I select the IP addresses of specific devices, say all device types called"tablet"
? How can I do that withmap
? -
silasjmatson over 11 yearsSorry about the duplicate answers, hit the backspace key one too many times and went back to a create rather than edit.
-
PJP over 11 yearsI'm curious, how do you differentiate a difference between
collect
andmap
? Also, doescollect(&ip)
return what you expect? -
silasjmatson over 11 yearsI usually use
collect
when I'm just grabbing values from a set of objects, andmap
when I'm doing a bunch of logic in the block, or returning an array that has changed values. Am I wrong on that? -
mu is too short over 11 yearsThe
select
-less version will leave you withnil
s. -
silasjmatson over 11 yearsOh, true. I didn't think about that too much.
-
PJP over 11 years
collect
is an alias tomap
; It doesn't matter which you use because they're identical. Any difference is most likely due to languages you've used in the past because of familiarity with one or the other. And, as a result, I usemap
because it's easier to type. -
Sk. Irfan almost 7 yearsNo need of using,
select
andmap
as mentioned in the Sergio Tulentsev's answer, as it will result in two loops and comparatively slower. -
Nick over 5 years
compact
also iterates over the array and checks each value fornil
. Sergio's answer could actually be faster. In your example, both iterations are over the full length ofclients
, whereas in Sergio's example, the second iteration may be over a smaller set. -
theartofbeing over 2 yearsThis is the correct answer for 2.7 and above