Combining arrays in Ruby - ruby

The following array contains two arrays each having 5 integer values:
[[1,2,3,4,5],[6,7,8,9,10]]
I want to combine these in such a way that it generates five different arrays by combining values of both arrays at index 0,1.. upto 4.
The output should be like this:
[[1,6],[2,7],[3,8],[4,9],[5,10]]
Is there any simplest way to do this?

What about transpose method?
a = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
#=> [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
a.transpose
#=> [[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]]
this method also can help you in future, as example:
a = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]]
#=> [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]]
a.transpose
#=> [[1, 6, 11], [2, 7, 12], [3, 8, 13], [4, 9, 14], [5, 10, 15]]

a = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
a.first.zip(a.last)

If you're sure your sub arrays have the same length, you can use Array#transpose :
[[1,2,3,4,5],[6,7,8,9,10]].transpose
#=> [[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]]
As a bonus, it works fine with more than 2 arrays :
[[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15]].transpose
#=> [[1, 6, 11], [2, 7, 12], [3, 8, 13], [4, 9, 14], [5, 10, 15]]
If you're not sure your sub arrays have the same length :
[[1,2,3,4,5],[6,7,8,9], [10,11]].reduce(&:zip).map(&:flatten)
#=> [[1, 6, 10], [2, 7, 11], [3, 8, nil], [4, 9, nil], [5, nil, nil]]
Using transpose in this example would throw an IndexError.

Using parallel assignment:
a, b = [[1, 2, 3, 4, 5],[6, 7, 8, 9, 10]]
a.zip b #=> [[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]]

Related

From multiple subsets, find all possible combinations of numbers to obtain a given sum

Though part of my question has been answered in this thread;
Finding all possible combinations of numbers to reach a given sum
there is one further function I'm looking for.
Scrolling down on that page for the ruby solution and more importantly the final line,
subset_sum([3,9,8,4,5,7,10],15)
I was wondering how you would go through multiple arrays, picking just one number from each array and coming to a set value.
The reason I ask is because I play a game called Heroclix. Each piece has a certain point value attributed to it and players make teams in multiples of one hundreds.
What I'm looking to avoid is using the same named character more than once in a team, just because they just so happen to have various point costs.
arr = [[1,2,3], [5,7,8], [4,9,13]]
target = 19
If you want just one solution:
arr[0].product(*arr[1..-1]).find { |a| a.reduce(:+) == target }
#=> [1, 5, 13]
If you want all solutions:
arr[0].product(*arr[1..-1]).select { |a| a.reduce(:+) == target }
#=> [[1, 5, 13], [2, 8, 9], [3, 7, 9]]
For both:
arr[0].product(*arr[1..-1])
#=> [[1, 5, 4], [1, 5, 9], [1, 5, 13], [1, 7, 4], [1, 7, 9], [1, 7, 13],
# [1, 8, 4], [1, 8, 9], [1, 8, 13], [2, 5, 4], [2, 5, 9], [2, 5, 13],
# [2, 7, 4], [2, 7, 9], [2, 7, 13], [2, 8, 4], [2, 8, 9], [2, 8, 13],
# [3, 5, 4], [3, 5, 9], [3, 5, 13], [3, 7, 4], [3, 7, 9], [3, 7, 13],
# [3, 8, 4], [3, 8, 9], [3, 8, 13]]
See Array#product.

Find every permutation of an array in Ruby, including permutations with sub arrays

Consider an array: [4, 6, 9]
Require all the permutations: (one, two and three digit ones)
[[9],
[6],
[4],
[9, 6],
[9, 4],
[6, 9],
[6, 4],
[4, 9],
[4, 6],
[9, 6, 4],
[9, 4, 6],
[6, 9, 4],
[6, 4, 9],
[4, 9, 6],
[4, 6, 9]]
Recording this question and my own finding as I didn't find anything simple enough while searching. Perhaps this may help someone:
a = [4, 6, 9]
(1..a.length).flat_map { |n| a.permutation(n).to_a }
And for every combination, just switch the method, like so:
a = [4, 6, 9]
(1..a.length).flat_map { |n| a.combination(n).to_a }

Nested Array Initialization && Assignment Oddity [duplicate]

This question already has an answer here:
Ruby Array Initialization [duplicate]
(1 answer)
Closed 3 years ago.
What is going on in the Array initialization that's causing the disparity in int assignment?
arr = Array.new(3) { Array.new(3) { Array.new(3) } }
3.times do |x|
3.times do |y|
3.times do |z|
arr[x][y][z] = Random.rand(1..9)
end
end
end
puts arr.to_s
#=> [[[3, 3, 1], [4, 9, 6], [2, 4, 7]], [[1, 6, 8], [9, 8, 5], [1, 7, 5]], [[2, 5, 9], [2, 8, 8], [9, 1, 8]]]
#=> [[[2, 4, 4], [6, 8, 9], [6, 2, 7]], [[2, 7, 7], [2, 1, 1], [8, 7, 7]], [[5, 3, 5], [3, 8, 1], [7, 6, 6]]]
#=> [[[4, 9, 1], [1, 6, 8], [9, 2, 5]], [[3, 7, 1], [7, 5, 4], [9, 9, 9]], [[6, 8, 2], [8, 2, 8], [2, 9, 9]]]
arr = Array.new(3, Array.new(3, Array.new(3)))
3.times do |x|
3.times do |y|
3.times do |z|
arr[x][y][z] = Random.rand(1..9)
end
end
end
puts arr.to_s
#=> [[[8, 2, 4], [8, 2, 4], [8, 2, 4]], [[8, 2, 4], [8, 2, 4], [8, 2, 4]], [[8, 2, 4], [8, 2, 4], [8, 2, 4]]]
#=> [[[2, 1, 4], [2, 1, 4], [2, 1, 4]], [[2, 1, 4], [2, 1, 4], [2, 1, 4]], [[2, 1, 4], [2, 1, 4], [2, 1, 4]]]
#=> [[[2, 7, 6], [2, 7, 6], [2, 7, 6]], [[2, 7, 6], [2, 7, 6], [2, 7, 6]], [[2, 7, 6], [2, 7, 6], [2, 7, 6]]]
When you use new(size=0, obj=nil) to initialize the array:
From the doc:
In the first form, if no arguments are sent, the new array will be
empty. When a size and an optional obj are sent, an array is created
with size copies of obj. Take notice that all elements will reference
the same object obj.
If you want multiple copy, then you should use the block version which uses the result of that block each time an element of the array needs to be initialized.

How can I combine elements of an array that have a common element?

I want to take an array of number pairs:
[[2, 3], [2, 15], [3, 15], [7, 8], [8, 7], [11, 15]]
and if two of these number pairs have a number in common, combine them and display the unique values, ultimately creating this array:
[[2, 3, 15, 11], [7, 8]]
Order of the numbers in the output array is not important. What would be the best solution?
The answer was corrected following Howard's comment.
[[2, 3], [2, 15], [3, 2], [3, 15], [7, 8], [8, 7], [11, 15], [15, 2], [15, 3], [15, 11]]
.each_with_object([]) do |e1, a|
a.select{|e2| (e1 & e2).any?}.each{|e2| e1.concat(a.delete(e2))}
e1.uniq!
a.push(e1)
end
# => [[8, 7], [15, 11, 3, 2]]
It's really just another mapping and sorting problem,:
array = [[2, 3], [2, 15], [3, 2], [3, 15], [7, 8], [8, 7], [11, 15], [15, 2], [15, 3], [15, 11]]
array.map{|a| array.each{|x| a |= x if (x & a).any?}; a.sort}.uniq
#=> [[2, 3, 11, 15], [7, 8]]
Not as elegant as #sawa's solution - but works for all the cases:
def includes? item, groups
groups.each{|sub|
return true if sub.include?(item)
}
false
end
def add groups, match, item
groups.each{|sub|
if sub.include?(match)
sub << item
sub.uniq!
return
end
}
end
def iterate arr
groups = []
grp = []
arr.each do |a,b|
grp = [a,b] if grp.empty?
if includes? a, groups
add groups, a, b
elsif includes? b, groups
add groups, b, a
else
groups << [a,b]
end
end
groups
end
arr = [[2, 3], [2, 15], [3, 2], [3, 15], [7, 8], [8, 7], [11, 15], [15, 2], [15, 3], [15, 11]]
p iterate(arr)
OUTPUT
[[2, 3, 15, 11], [7, 8]]
A recursive solution:
def doit(a,b)
return a unless b
h = b.group_by {|e| (a[-1] & e).any?}
h[true] ? a[-1] |= h[true].flatten : a << h[false].pop
doit(a, h[false])
end
arr = [[2, 3], [2, 15], [3, 2], [3, 15], [16, 21], [7, 8], [8, 7], \
[21, 44], [11, 15], [15, 2], [15, 3], [15, 11], [8, 9]]
doit([arr.pop], arr) # => [[8, 9, 7], [15, 11, 2, 3], [21, 44, 16]]

Extract 2D sub-array (without using Matrix)

In Ruby, given an array-of-arrays representing a 2D grid of numbers, how would you extract a specific sub-2D array?
a = [[0, 3, 1, 5, 5],
[4, 6, 8, 3, 5],
[7, 1, 4, 0, 8],
[0, 8, 8, 7, 4],
[7, 2, 4, 5, 4]]
require 'pp'
pp sub_array(a,1..4,2..4)
#=> [[8, 3, 5],
#=> [4, 0, 8],
#=> [8, 7, 4],
#=> [4, 5, 4]]
This is 'easy' to do using the Matrix library:
m = Matrix[*a]
p m.minor(1..4,2..4).to_a
#=> [[8, 3, 5], [4, 0, 8], [8, 7, 4], [4, 5, 4]]
However, I feel certain that there's an elegant way to do this without using the Matrix, perhaps involving zip or transpose :)
I'm including the words "two-dimensional" here for search hits.
def sub_array(xs, rows, columns)
xs[rows].map { |row| row[columns] }
end
sub_array(a, 1..4, 2..4)
#=> [[8, 3, 5], [4, 0, 8], [8, 7, 4], [4, 5, 4]]

Resources