1

I'm fairly new to learning Ruby so please bear with me. I am working on a 7 kyu Ruby coding challenge and I've been tasked with finding how many people are left on the bus (first value represents people on, second value, people off) please look at comments in code for more detail.

below is a test example:

([[10, 0], [3, 5], [5, 8]]), # => should return 5"

This is my solution so far:

def number(bus_stops)
   bus_stops.each{ | on, off |  on[0] -= off[1] }
end

bus_stops

# loop through the array
# for the first array in the nested array subtract second value from first
# add the sum of last nested array to first value of second array and repeat  
# subtract value of last element in nested array and repeat 

How can I approach this? any resources you would recommend?

2
  • When you give an example it is helpful to assign a variable to all inputs (e.g., arr = [[10, 0], [3, 5], [5, 8]]). That way readers can refer to the variables (e.g., arr) in answers and comments without having define them. Also, inputs should all be valid Ruby objects. Yours is not valid, because of the comma, and the parentheses are superfluous. The expected result should always be shown, which here you have done. Commented Sep 3, 2020 at 18:33
  • thank you, will do next time. Commented Sep 4, 2020 at 9:27

3 Answers 3

1

There would be many ways to achieve this. Here is one with inject

arr.map { |inner_array| inner_array.inject(&:-) }.inject(&:+)

Iterate over the arrays and calculate the count at each position of how many people would have been left on the bus (this can return negative integers). This will return

[10, -2, -3]
[10 on, none off][3 on, 5 off][5 on, 8 off]

Then inject a + operator between each element to calculate the sum of people left on the bus. This only works if you count from 0 people on and 0 people off.

Sign up to request clarification or add additional context in comments.

2 Comments

Note that inject does not require a block, it can also take the operation name as a Symbol, e.g. arr.map { |inner_array| inner_array.inject(:-) }.inject(:+). Also, the outer inject is just sum: arr.map { |inner_array| inner_array.inject(:-) }.sum
Correct, note sum is only available in ruby 2.4 and higher (IIRC)
1

Here are two other ways to compute the desired result.

arr = [[10, 0], [3, 5], [5, 8]]

Use Array#transpose

arr.transpose.map(&:sum).reduce(:-)
  #=> 5

The steps are as follows.

a = arr.transpose
  #=> [[10, 3, 5], [0, 5, 8]]
b = a.map(&:sum)
  #=> [18, 13] ([total ons, total offs]) 
b.reduce(:-)
  #=> 5 

Use Matrix methods

require 'matrix'

(Matrix.row_vector([1] * arr.size) * Matrix[*arr] * Matrix.column_vector([1,-1]))[0,0]
  #=> 5

The steps are as follows.

a = [1] * arr.size
  #=> [1, 1, 1] 
b = Matrix.row_vector(a)
  #=> Matrix[[1, 1, 1]] 
c = Matrix[*arr]
  #=> Matrix[[10, 0], [3, 5], [5, 8]]
d = b * c
  #=> Matrix[[18, 13]]  
e = Matrix.column_vector([1,-1])
  #=> Matrix[[1], [-1]] 
f = d * e
  #=> Matrix[[5]] 
f[0,0]
  #=> 5 

See Matrix::[], Matrix::row_vector, Matrix::column_vector and Matrix#[]. Notice that the instance method [] is documented in Object.

1 Comment

I was unable to locate the Ruby doc for the instance method Matrix#* (matrix. multiplication). Can a reader help?
1

sum takes a block, which is really simple in this case:

arr = [[10, 0], [3, 5], [5, 8]]
p arr.sum{|on, off| on - off}  # => 5

So you were very close.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.