Merge and Interleave Two Arrays in Ruby

Merge and interleave two arrays in Ruby

You can do that with:

a.zip(s).flatten.compact

Unequally interleave two ruby arrays

a.each_slice(2).zip(b).flatten
#=> [1, 2, "a", 3, 4, "b", 5, 6, "c"]

Ruby, equally distribute elements and interleave/merge multiple arrays

I would use a sort to do this, based on element index postion, divided by size of array, plus some offset based on array id, to keep things consistent (if you don't need consistency, you could use a small random offset instead).

a = [:a,:b]
b = [:c]
c = [:d,:e,:f]
d = [:g:,:h,:i,:j]

def sort_pos array, id
(1..array.size).map { |i| (i - 0.5 + id/1000.0)/(array.size + 1e-6) }
end

# Combine all the arrays with their sort index, assigning ids to each array for consistency.
# Depending on how you receive these arrays, this structure can be built up programatically,
# as long as you add an array plus its sort index numbers at the same time
combined = (a + b + c + d).zip( sort_pos(a, 1) + sort_pos(b, 2) + sort_pos(c, 3) + sort_pos(d, 4) )


# Extract the values from the original arrays in their new order
combined.sort_by { |zipped| zipped[1] }.map { |zipped| zipped[0] }

=> [:g, :d, :a, :h, :e, :i, :b, :f, :j, :c]

There might be a cleaner way of doing this in Ruby . . . but I think the end result is what you are after - an "even" mix of multiple arrays.

If you only care about even-ness of mix from a statistical perspective (i.e. over time it is "fair"), you could just do this:

(a+b+c+d).shuffle

=> [:g, :b, :i, :c, :a, :h, :e, :j, :f, :d]

Ruby - Merge two arrays and remove values that have duplicate

You can do the following!

# Merging
c = a + b
=> [1, 2, 3, 4, 5, 2, 4, 6]
# Removing the value of other array
# (a & b) is getting the common element from these two arrays
c - (a & b)
=> [1, 3, 5, 6]

Dmitri's comment is also same though I came up with my idea independently.

How do I combine two arrays based on the index of their elements?

From the docs:

If the size of any argument is less than the size of the initial array, nil values are supplied.

So you do not need to worry about the case where the second array is shorter.

If the first array is shorter, pad it out with nil to the length of the second array.

You can use compact to remove the superfluous nils afterwards.

Case 1: a is longer

a = [1, 2, 3, 4, 5]
b = [6, 7, 8]

a[b.count-1] ||= nil
a.zip(b).map(&:flatten).map(&:compact)

Result:

[[1, 6], [2, 7], [3, 8], [4], [5]]

Case 2: b is longer

a = [1, 2, 3]
b = [4, 5, 6, 7, 8]

a[b.count-1] ||= nil
a.zip(b).map(&:flatten).map(&:compact)

Result:

[[1, 4], [2, 5], [3, 6], [7], [8]]   

Variation with nil included

a = [1, 2, 3, 4, 5]
b = [6, 7, 8]

a[b.count-1] ||= nil
b[a.count-1] ||= nil
a.zip(b).map(&:flatten) # [[1, 6], [2, 7], [3, 8], [4, nil], [5, nil]]

... and ...

a = [1, 2, 3]
b = [4, 5, 6, 7, 8]

a[b.count-1] ||= nil
b[a.count-1] ||= nil
a.zip(b).map(&:flatten) # [[1, 4], [2, 5], [3, 6], [nil, 7], [nil, 8]]

Notes

  • If a or b must not be modified, insert a .clone somewhere to clone them beforehand.
  • The .flatten was taken from the OP's example; it flattens any arrays that take the role of the integers in the example. Keep or leave off as needed.

How to combine the sorting of two arrays into one?

To replicate the functionality you have (all authors, sorted, on top of all books, sorted,) you might use that nil is falsey in ruby.

author.concat(book).sort_by do |a|
if a.instance_of? Author
[1, a.name || -1, a.amount || -1]
else
[0, a.data || -1, a.price || -1]
end
end

Note that I put leading 1 for authors and 0 for books to preserve all the authors come before all the books.

Combine two arrays in Ruby?

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}]]


Related Topics



Leave a reply



Submit