How to Transpose Different Sized Ruby Arrays

How can I transpose different sized ruby arrays?

A similar answer was posted (but deleted) an hour earlier:

arr = [[1, 2, 3], [4, 5], [6]]

arr[0].zip(*arr[1..-1])
#=> [[1, 4, 6], [2, 5, nil], [3, nil, nil]]

The above is equivalent to:

[1, 2, 3].zip([4, 5], [6])

This approach assumes that your first sub-array is always the longest. Otherwise the result will be truncated:

arr = [[1, 2], [3, 4, 5], [6]]

arr[0].zip(*arr[1..-1])
#=> [[1, 3, 6], [2, 4, nil]] missing: [nil, 5, nil]

Why does Ruby have zip and transpose when they do the same thing?

#transpose Assumes that self is an array of arrays and transposes the rows and columns.

#zip assumes self can be any Enumerable object.

More differences are here

a = [12,11,21]
b = [1,2]

[a,b].transpose # transpose': element size differs (2 should be 3) (IndexError)
a.zip(b) # => [[12, 1], [11, 2], [21, nil]]
b.zip(a) # => [[1, 12], [2, 11]]

That to apply the #transpose method a and b should be of the same size. But for applying #zip, it is not needed b to be of the same size of a, ie b and a can be of any of size.

With #zip, the resultant array size will always be the size of self. With #transpose the resulting array size will be any of the inner array's size of self.

How do I transpose multiple arrays unless an array element is empty?

Consider this :

arr1 = ["a", "b"]
arr2 = ["", "c"]
arr3 = ["d", "e"]

Now, as per your requirement,; you want those tranposed arrays where arr2 blank value is not present.

Use #reject to do that as:

[arr1, arr2, arr3].transpose.reject{ |x| x[1].empty? }

Here, x[1] corresponds to the second element in each transposed array; and it comes from arr2; so here, we rejected all those instances where "" was present in arr2.

Hope it helps

How to interleave arrays of different length in Ruby

If the source arrays don't have nil in them, you only need to extend the first array with nils, zip will automatically pad the others with nil. This also means you get to use compact to clean the extra entries out which is hopefully more efficient than explicit loops

def interleave(a,*args)
max_length = args.map(&:size).max
padding = [nil]*[max_length-a.size, 0].max
(a+padding).zip(*args).flatten.compact
end

Here is a slightly more complicated version that works if the arrays do contain nil

def interleave(*args)
max_length = args.map(&:size).max
pad = Object.new()
args = args.map{|a| a.dup.fill(pad,(a.size...max_length))}
([pad]*max_length).zip(*args).flatten-[pad]
end

Ruby array from two different sized arrays?

bus_times = days.zip(trips.each_slice(3)).flatten

or if you want to keep them as an array of arrays:

bus_times = days.zip(trips.each_slice(3)).map(&:flatten)

What is the best way to merge two arrays (element + element), if elements itself are arrays

[Array1, Array2].transpose.map(&:flatten) 
=> [[1, 2, 1, 4], [8, 11], [2, 3, 3, 6]]

RubyGuides: "Turn Rows Into Columns With The Ruby Transpose Method"


Each step explained:

[Array1, Array2]
=> [[[1, 2], [], [2, 3]],
[[1, 4], [8, 11], [3, 6]]]

Create a grid like array.

[Array1, Array2].transpose
=> [[[1, 2], [1, 4]], [[], [8, 11]], [[2, 3], [3, 6]]]

transpose switches rows and columns (close to what we want)

[Array1, Array2].transpose.map(&:flatten)
=> [[1, 2, 1, 4], [8, 11], [2, 3, 3, 6]]

flatten gets rid of the unnecessary nested arrays (here combined with map to access nested arrays)

How to swap columns and rows in a matrix with Ruby

Move j = 0 within the i loop

def my_transpose(matrix)

new_matrix = []

i = 0

while i < matrix.size
new_matrix[i] = []
j = 0 # move this here
while j < matrix.size
new_matrix[i] << matrix[j][i]
j += 1
end
i += 1
end

return new_matrix
end

If j is not reset to 0 for every i loop then it never enters the j loop except for the first time:

i = 0
j = 0
# Enter i loop
new_matrix[0] = []
# Enter j loop
new_matrix[0] << matrix[0][0]
j += 1 #=> 1

new_matrix[0] << matrix[1][0]
j += 1 #=> 2

new_matrix[0] << matrix[2][0]
j += 1 #=> 3
# Exit j loop
i += 1 #=> 1

new_matrix[1] = []
# Does not enter j loop as j = 3 > matrix.size
i += 1 #=> 2

new_matrix[2] = []
# Does not enter j loop as j = 3 > matrix.size
i += 1 #=> 3
# Exit i loop

Converting uneven rows to columns with FasterCSV

I would insert nulls to fill the holes in your matrix, something such as:

a = [[1, 2, 3], [3, 4]]

# This would throw the error you're talking about
# a.transpose

# Largest row
size = a.max { |r1, r2| r1.size <=> r2.size }.size

# Enlarge matrix inserting nils as needed
a.each { |r| r[size - 1] ||= nil }

# So now a == [[1, 2, 3], [3, 4, nil]]
aa = a.transpose

# aa == [[1, 3], [2, 4], [3, nil]]


Related Topics



Leave a reply



Submit