Why can't Ruby's reduce method calculate from 2 to 4? - ruby

I want to perform a simple calculation of 2+3+4, so I wrote the following code. However, when I put the result of list, I only get "2 3 4". May I ask where did I have the problem?
list = [2, 3, 4]
list.reduce(0) {|start, i| start + i }
puts list

method reduce returns the result but you're not using it. list stays your list, reduce do not alter it
list = [2, 3, 4]
sum = list.reduce(0) { |start, i| start + i }
puts sum

Related

How to find the sum of each row for a multi-dimensional array

I would like to find the sum of each row of a multidimensional array, and have the sums an array, e.g., for [[1,2,3],[1,1,1]], I would like to get [6,3].
I tried the following:
arr = [[1,2,3],[3,2,1],[2,1,3]]
print arr.each{|row| row.each{|column| puts column}}
Results:
1
2
3
3
2
1
2
1
3
[[1, 2, 3], [3, 2, 1], [2, 1, 3]]
I am struggling with it. I still don't fully understand each iterators. Any help would be appreciated.
For ruby 2.4.0 or newer
a.map { |suba| suba.sum }
or simply
a.map(&:sum)
for ruby prior to 2.4.0
a.map { |suba| suba.inject(0, :+) }
[[1,2,3],[1,1,1]].map{|a| a.inject(:+)} # => [6, 3]
If there is a possibility that any of the sub-array can be empty, then you need to add the initial 0, as Ursus pointed out.
[[1,2,3],[1,1,1]].map{|a| a.inject(0, :+)} # => [6, 3]
[[1,2,3],[1,1,1]].map { |a| a.inject(0, :+) } # => [6 , 3]
map changes each element to the return value of this elements block
get the sum for each array with inject(:+)
use inject(0, :+) to set 0 instead of the first element as the start value (handles empty inner array)
see:
Enumerable#inject
Enumerable#map
"How to find the sum of each row"
arr = [[1,2,3], [1,1,1]]
print arr.each{|row| <-- here you have each row
So now row contains [1,2,3] initially. As others have mentioned, you can apply a sum here. (You don't need the leading print).
arr.each{|row| puts row.sum}
Result:
6
3
But a better way to do it is with map. As I told a Ruby newbie many years ago, think of map when you want to change every element to something else, in other words a "1:1 mapping" of input to output. In this case the output is row.sum:
sums = arr.map{|row| row.sum}
Result:
[6, 3]

Ruby: Avoiding infinite loop in an array that doubles each number

So there is an infinte loop here, but I'm not seeing it.
# Return an array that doubles each number
numbers = [1, 2, 3, 4]
numbers.each do |number|
numbers << number * 2
end
puts numbers
I understand there are shorter ways to do this, but I am learning so it's all written out more explicitly.
You're adding elements to an array while iterating over that array. It's therefore impossible to reach the end.
What you need to do is use the map function:
numbers.map! do |n|
n * 2
end
That updates each entry in place with its value times two.
If you're looking to add on a single set of doubled numbers:
numbers += numbers.map do |n|
n * 2
end
That adds on a copy of the array that's been doubled.
Edit: Instead of using map, for academic illustration purposes, you can try using a copy with dup:
numbers.dup.each do |n|
numbers << n * 2
end
You can also iterate over it sequentially:
numbers.each_index do |i|
numbers << numbers[i] * 2
end
These are all far less efficient and are much harder to read than the map version.
You cant see the process since this infinity lasts forever and never reaches your puts numbers statement. Thats why you cant see it in the console.
Try something like:
numbers = [1, 2, 3, 4]
numbers.each do |number|
numbers << number * 2
puts numbers
end
To see your pc going mad :)
by pushing the doubled value in the array you are increasing the array size each time by 1. hence infinite loop is occurring. I think what you really want to do is
numbers.each do |num|
puts num *2
end
Return an array that doubles each number
Assuming you don't want to use map, you can use Enumerable#each_with_object:
numbers = [1, 2, 3, 4]
numbers.each_with_object([]) { |n, o| o << n + n }
#=> [2, 4, 6, 8]
Since nobody mentioned the obvious answer, here it is :
numbers = [1, 2, 3, 4]
double_numbers = []
numbers.each do |number|
double_numbers << number * 2
end
p double_numbers
# [2, 4, 6, 8]
This would be the way to do it if you didn't know about map or map!. Note that you iterate on one array and create another one in order to avoid messing with the each loop.

Ruby - pushing values from an array combination to a new array

I am trying to print all the different sums of all combinations in this array [1,2,3]. I want to first push every sum result to a new array b, then print them using b.uniq so that non of the sum results are repeated.
However, with the code I have, the 3 repeats itself, and I think it is because of the way it is pushed into the array b.
Is there a better way of doing this?
a = [1,2,3]
b = []
b.push a
b.push a.combination(2).collect {|a,b| (a+b)}
b.push a.combination(3).collect {|a,b,c| (a+b+c)}
puts b.uniq
p b #[[1, 2, 3], [3, 4, 5], [6]]
Can someone please help me with this? I am still new in ruby.
Because an Array of arbitrary length can be summed using inject(:+), we can create a more general solution by iterating over the range 1..n, where n is the length of the Array.
(1..(a.size)).flat_map do |n|
a.combination(n).map { |c| c.inject(&:+) }
end.uniq
#=> [1, 2, 3, 4, 5, 6]
By using flat_map, we can avoid getting the nested Array result, and can call uniq directly on it. Another option to ensure uniqueness would be to pass the result to a Set, for which Ruby guarantees uniqueness internally.
require "set"
sums = (1..(a.size)).flat_map do |n|
a.combination(n).map { |c| c.inject(&:+) }
end
Set.new(sums)
#=> #<Set: {1, 2, 3, 4, 5, 6}>
This will work for an any Array, as long as all elements are Fixnum.
If all you want is an array of the possible sums, flatten the array before getting the unique values.
puts b.flatten.uniq
What is happening is uniq is running over a multi-dimensional array. This causes it to look for duplicate arrays in your array. You'll need the array to be flattened first.

Iterate every two elements in ruby for loop

How do you create a for loop like
for (int x=0; x<data.length; x+=2)
in ruby? I want to iterate through an array but have my counter increment by two instead of one.
If what you really want is to consume 2 items from an array at a time, check out each_slice.
[1,2,3,4,5,6,7,8,9].each_slice(2) do |a, b|
puts "#{a}, #{b}"
end
# result
1, 2
3, 4
5, 6
7, 8
9,
Ruby's step is your friend:
0.step(data.length, 2).to_a
=> [0, 2, 4, 6]
I'm using to_a to show what values this would return. In real life step is an enumerator, so we'd use it like:
data = [0, 1, 2, 3, 4, 5]
0.step(data.length, 2).each do |i|
puts data[i]
end
Which outputs:
0
2
4
<== a nil
Notice that data contains six elements, so data.length returns 6, but an array is a zero-offset, so the last element would be element #5. We only get three values, plus a nil which would display as an empty line when printed, which would be element #6:
data[6]
=> nil
That's why we don't usually walk arrays and container using outside iterators in Ruby; It's too easy to fall off the end. Instead, use each and similar constructs, which always do the right thing.
To continue to use step and deal with the zero-offset for arrays and containers, you could use:
0.step(data.length - 1, 2)
but I'd still try working with each and other array iterators as a first choice, which #SergioTulentsev was giving as an example.
(0..data.length).step(2) do |x|
puts x
end
This seems like the closest substitute.
Using Range#step:
a = (1..50).to_a
(1..a.size).step(2).map{|i| a[i-1]} # [1, 3, 5, 7, 9 ...

Whats the best way to split an array in ruby into multiple smaller arrays of random size

I have multiple arrays in ruby of variable length from 1 to 40 :
#items is a typical array which could be anywhere from 1 to 40 in length. eg
#items = [1, 2, 3, 4, 5, 6]
I want to randomly split the array into smaller arrays of lengths either 1, 2 or 3 to give a result of (for example)
#items = [[1, 2],[3],[4,5,6]]
or
#items = [[1],[2, 3],[4],[5,6]]
etc
I know you can split the array using #items.each_slice(3)... where 3 is a fixed length. But i want to randomly split large arrays of variable length into array sizes of 1,2 or 3 randomly... Whats the best way to achieve this?
items, #items = #items.dup, []
#items.push(items.shift(rand(1..3))) until items.empty?
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = []
until a.empty?
b << a.shift((1..a.size).to_a.sample)
end
# b => [[1, 2], [3, 4, 5, 6, 7], [8, 9], [10]]
# change everytime though
You can limit the sub arrays size by replacing the a.size with 3 or anything you want.
This solution maybe uses too many local variables, but it is non-destructive to the input array and flexible on array window maximum.
def rotateAndTake inputArray, windowSize
rotator, returnArray, breaker = 0, [], true
while breaker do
window = rand(windowSize)+1
if(rotator + window > inputArray.length) then
window = inputArray.length - rotator
breaker = false
end
returnArray << inputArray.rotate(rotator).take(window) if window > 0
rotator += window
end
returnArray
end
Also, I just wanted to write a solution that used the "rotate" method.
Just for yucks, I thought I'd try a pure functional form with no mutating methods for this problem:
( (0..#items.size)
.inject([0]) { |m,_| m + [m.last + 1 + rand(3)] }
.take_while { |i| i < #items.size } + [#items.size] ).
each_cons(2).
map { |s,e| #items[s...e] }
Here's another functional solution:
( [0]+
(1..a.length-1)
.to_a
.sample(rand(a.length))
.sort+
[a.length]
).each_cons(2).map{|i,j| a[i..j-1]}

Resources