Suppose we have two arrays:
foo = [1, 2] # can be mapped in [{id: 1}, {id: 2}]
bar = [{id: 2}, {id: 4}]
As a result I need to get following array:
res = [ [1, nil], [2, {id: 2}], [nil, {id: 4}] ]
# Is also ok [ [{id: 1}, nil], [{id: 2}, {id: 2}], [nil, {id: 4}] ]
I there any standard Ruby method to get such combinations? At first I'm looking for Ruby way, elegant, short solution.
In other words, I need to get an array diff map, which shows absent and newly added elements.
The elements:
elements = (foo + bar.map{ |h| h.values.first }).uniq
#=> [1, 2, 4]
and the combinations:
elements.map { |i| [foo.include?(i) ? i : nil, bar.include?({id: i}) ? {id: i} : nil] }
#=> [[1, nil], [2, {:id=>2}], [nil, {:id=>4}]]
Or as Sebastian suggested, you can also use #find
instead of #includes?
:
elements.map { |i| [foo.find { |e| e == i }, bar.find { |e| e == { id: i } }] }
I would transform the two arrays to lookup hashes. Then collect all the ids to iterate. Map the ids into the foo
and bar
values, then zip them together.
foo_lookup = foo.to_h { |id| [id, {id: id}] } # change `{id: id}` into `id` for the other output
bar_lookup = bar.to_h { |item| [item[:id], item] }
ids = foo_lookup.keys | bar_lookup.keys
res = ids.map(&foo_lookup).zip(ids.map(&bar_lookup))
#=> [[{:id=>1}, nil], [{:id=>2}, {:id=>2}], [nil, {:id=>4}]]
Just another option.
foo = [1, 2]
bar = [{id: 2}, {id: 4}]
(foo + bar).group_by { |e| e.is_a?(Hash) ? e[:id] : e }.values.map { |e| e.size == 1 ? e << nil : e }
#=> [[1, nil], [2, {:id=>2}], [{:id=>4}, nil]]
The first part returns
(foo + bar).group_by { |e| e.is_a?(Hash) ? e[:id] : e }.values
#=> [[1], [2, {:id=>2}], [{:id=>4}]]
If you need to sort the sub arrays, just map using Array#unshift or Array#push (prepend or append nil
) depending in the element already there.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.