Ruby method to sum all values in a multidimensional array - arrays

I am trying to sum the elements of an array. WITHOUT using flatten. I have tried using the following:
def multi_array_sum(arr)
sum = 0
arr.each do |row|
row.each do |column|
sum += column
end
end
return sum
end
but unfortunately, it is not working. I am not sure how to iterate though a multidimensional array considering that I cannot use each if the first element in the array is not another array itself, for example, array = [[1, [1, 2], [3, 4, 5]].

If all elements are numeric or arrays, and you want to sum them all:
array.flatten.inject(:+)

Just use standard array functions and then enumerable.
array.flatten.reduce(:+)

If you are 100% sure that you cannot use flatten then you can use:
array.map { |a| a.reduce(:+) }.reduce(:+)

So if you absolutely can't use flatten (which is a bit weird), you can use a simple recursive method:
def multi_array_sum(arr)
case arr
when Fixnum
arr
when Array
arr.reduce(0) { |agg, sub_arr| agg + multi_array_sum(sub_arr) }
end
end

If each inner array is the same size and contains only numbers, you could use the method Matrix#[] to convert the array to a matrix, Matrix#each (without a block) to create an enumerator to generate the elements of the matrix, and Enumerable#reduce (aka inject) to compute the sum of all elements of the matrix.
require 'matrix'
def sum_all(arr)
Matrix[*arr].each.reduce(:+)
end
sum_all [[1,2],[3,4]] #=> 10

Related

looping through nested arrays and accessing elements RUBY

I want to iterate through a nested array and operate on each element, so square each number in this case. I know how to do it for a normal array but for some reason i am getting undefined map method when include deeper iteration to access the inner arrays. Am a newbie too so if you could explain how it works that would help my learning. Thanks
def SquareArrayElements(n)
n.each do |number|
number.map do |num|
squared_nums = num * num
end
end
squared_nums
end
SquareArrayElements([10,[[10],10],[10]])
Since you've said in the comments that:
i want to square the 10s and return them to one array =>[100,100,100,100].
I assume that you don't need to preserve the original arrays and just want one array with the squared results. If that's the case you can #flatten the array and then square the numbers:
def square_array(arr)
arr.flatten.map { |e| e ** 2 }
end
square_array([10,[[10],10],[10]])
#=> [100, 100, 100, 100]
You only need to call map on the arrays, not on the integers. That's why you're getting an undefined map method, integers don't support that method.
Try
def square_array(element)
if element.responds_to?(:map)
element.map{|m| square_array(m)}
else
element * element
end
end

Splitting a hash variable with reduce

When invoking reduce on an array of hashes, I thought I could split the hash by key and value within the parameters using the () technique. But in this case, it does not appear to work:
columns = [
{"lead"=>["source", 2]},
{"parent"=>["name", 4]}
]
columns.reduce({}) do |acc, (k,v)|
puts "k #{k} v #{v}"
end
# k {"lead"=>["source", 2]} v
# k {"parent"=>["name", 4]} v
# => nil
I expected k to be "lead" and v to be ["source", 2]. Because columns is an array and not a hash, I cannot do this (k,v) to get the key/value pair of hash. Is there another technique I can use in argument list in order to pass the k/v pair rather than having to dissect it in the block?
It happens because the logic behind this parenthesis is basically a parallel assignment, which doesn't work in your case because each item in the collection is a hash. So practically what you can do it convert each item to array instead:
columns = columns.flat_map(&:to_a)
Demonstration

Other ways of converting part of array to subarray in Ruby?

When parsing CSV file I need to combine fields of a row into an array starting from 4th field (3rd array element). I want to manipulate each row as in example below:
Original array:
array1 = [1,2,3,4,5]
Changed array:
array2 = [1,2,3,[4,5]]
My code is here:
array1[0..2].push(array1[3..array1.length])
=> [1, 2, 3, [4, 5]]
My question is: Is there a better/cleaner/simpler way to convert part of an array into subarray?
There is! You can do this
a = a[0..2] + [a[3..-1]]. In ruby + can be used to concatenate arrays. Additionally, n..-1 gives you elements n to the end of the array. As a caveat, + is slower and more expensive than concat so if you were to do a[0..2].concat([a[3..-1]) it will be cheaper and faster.

Find the index by current sort order of an array in ruby

If there is an array
array A = ["a","b","c","d"] #Index is [0,1,2,3]
And it's sorted to.
array A = ["d","c","b","a"]
I need an array that returns me the updated index based on the sorted order
[3,2,1,0]
I'm trying to find a solution to this ruby
UPDATE to the question
If a is sorted to
array A = ["d","b","c","a"] #not a pure reverse
Then the returned index array should be
[3,1,2,0]
You need to create a mapping table that preserves the original order, then use that order to un-map the re-ordered version:
orig = %w[ a b c d ]
orig_order = orig.each_with_index.to_h
revised = %w[ d c b a ]
revised.map { |e| orig_order[e] }
# => [3, 2, 1, 0]
So long as your elements are unique this will be able to track any shift in order.
Here is one way to do this:
original_array = ["a","b","c","d"]
jumbled_array = original_array.shuffle
jumbled_array.map {|i| original_array.index(i)}
#=> [1, 3, 0, 2]
Note:
In this sample, output will change for every run as we are using shuffle to demonstrate the solution.
The solution will work only as long as array has no duplicate values.
If you do wish to solution to work with arrays with duplicate values, then, one possibility is to look at object_id of array members while figuring out the index.
jumbled_array.map {|i| original_array.map(&:object_id).index(i.object_id)}
This solution will work as long as jumbled_array contains element from original_array and no elements were recreated using dup or something that results in change in object_id values
You can use the map and index methods.
arr = ["a","b","c","d"]
sort_arr = ["d","c","b","a"]
sort_arr.map{|s| arr.index(s)}
# => [3, 2, 1, 0]

Convert Array to Array of Arrays

I have an array like this one:
array = ['john', 'jennifer', 'kristen', 'ted']
I would like to convert it to an array of arrays of k elements.
For example, if k = 2 the result should be:
[['john', 'jennifer'], ['kristen', 'ted']]
Is it possible to do so in one line?
each_slice might help:
array.each_slice(2).to_a
#=> [["john", "jennifer"], ["kristen", "ted"]]
If you want to create two arrays from one with a predicate (an expression which evaluates to either true or false), I would recommend partition
array.partition{ |name| name[0] == 'j' }
#=> [["john", "jennifer"], ["kristen", "ted"]]

Resources