Need a simple explanation of the inject method - ruby

[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
I'm looking at this code but my brain is not registering how the number 10 can become the result. Would someone mind explaining what's happening here?

You can think of the first block argument as an accumulator: the result of each run of the block is stored in the accumulator and then passed to the next execution of the block. In the case of the code shown above, you are defaulting the accumulator, result, to 0. Each run of the block adds the given number to the current total and then stores the result back into the accumulator. The next block call has this new value, adds to it, stores it again, and repeats.
At the end of the process, inject returns the accumulator, which in this case is the sum of all the values in the array, or 10.
Here's another simple example to create a hash from an array of objects, keyed by their string representation:
[1,"a",Object.new,:hi].inject({}) do |hash, item|
hash[item.to_s] = item
hash
end
In this case, we are defaulting our accumulator to an empty hash, then populating it each time the block executes. Notice we must return the hash as the last line of the block, because the result of the block will be stored back in the accumulator.

inject takes a value to start with (the 0 in your example), and a block, and it runs that block once for each element of the list.
On the first iteration, it passes in the value you provided as the starting value, and the first element of the list, and it saves the value that your block returned (in this case result + element).
It then runs the block again, passing in the result from the first iteration as the first argument, and the second element from the list as the second argument, again saving the result.
It continues this way until it has consumed all elements of the list.
The easiest way to explain this may be to show how each step works, for your example; this is an imaginary set of steps showing how this result could be evaluated:
[1, 2, 3, 4].inject(0) { |result, element| result + element }
[2, 3, 4].inject(0 + 1) { |result, element| result + element }
[3, 4].inject((0 + 1) + 2) { |result, element| result + element }
[4].inject(((0 + 1) + 2) + 3) { |result, element| result + element }
[].inject((((0 + 1) + 2) + 3) + 4) { |result, element| result + element }
(((0 + 1) + 2) + 3) + 4
10

The syntax for the inject method is as follows:
inject (value_initial) { |result_memo, object| block }
Let's solve the above example i.e.
[1, 2, 3, 4].inject(0) { |result, element| result + element }
which gives the 10 as the output.
So, before starting let's see what are the values stored in each variables:
result = 0 The zero came from inject(value) which is 0
element = 1 It is first element of the array.
Okey!!! So, let's start understanding the above example
Step :1 [1, 2, 3, 4].inject(0) { |0, 1| 0 + 1 }
Step :2 [1, 2, 3, 4].inject(0) { |1, 2| 1 + 2 }
Step :3 [1, 2, 3, 4].inject(0) { |3, 3| 3 + 3 }
Step :4 [1, 2, 3, 4].inject(0) { |6, 4| 6 + 4 }
Step :5 [1, 2, 3, 4].inject(0) { |10, Now no elements left in the array, so it'll return 10 from this step| }
Here Bold-Italic values are elements fetch from array and the simply Bold values are the resultant values.
I hope that you understand the working of the #inject method of the #ruby.

The code iterates over the four elements within the array and adds the previous result to the current element:
1 + 2 = 3
3 + 3 = 6
6 + 4 = 10

What they said, but note also that you do not always need to provide a "starting value":
[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
is the same as
[1, 2, 3, 4].inject { |result, element| result + element } # => 10
Try it, I'll wait.
When no argument is passed to inject, the first two elements are passed into the first iteration. In the example above, result is 1 and element is 2 the first time around, so one less call is made to the block.

The number you put inside your () of inject represents a starting place, it could be 0 or 1000.
Inside the pipes you have two place holders |x, y|. x = what ever number you had inside the .inject('x'), and the secound represents each iteration of your object.
[1, 2, 3, 4].inject(5) { |result, element| result + element } # => 15
1 + 5 = 6
2 + 6 = 8
3 + 8 = 11
11 + 4 = 15

Inject applies the block
result + element
to each item in the array. For the next item ("element"), the value returned from the block is "result". The way you've called it (with a parameter), "result" starts with the value of that parameter. So the effect is adding the elements up.

tldr; inject differs from map in one important way: inject returns the value of the last execution of the block whereas map returns the array it iterated over.
More than that the value of each block execution passed into the next execution via the first parameter (result in this case) and you can initialize that value (the (0) part).
Your above example could be written using map like this:
result = 0 # initialize result
[1, 2, 3, 4].map { |element| result += element }
# result => 10
Same effect but inject is more concise here.
You'll often find an assignment happens in the map block, whereas an evaluation happens in the inject block.
Which method you choose depends on the scope you want for result. When to not use it would be something like this:
result = [1, 2, 3, 4].inject(0) { |x, element| x + element }
You might be like all, "Lookie me, I just combined that all into one line," but you also temporarily allocated memory for x as a scratch variable that wasn't necessary since you already had result to work with.

[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
is equivalent to the following:
def my_function(r, e)
r+e
end
a = [1, 2, 3, 4]
result = 0
a.each do |value|
result = my_function(result, value)
end

[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
In plain English, you are going through (iterating) through this array ([1,2,3,4]). You will iterate through this array 4 times, because there are 4 elements (1, 2, 3, and 4). The inject method has 1 argument (the number 0), and you will add that argument to the 1st element (0 + 1. This equals 1). 1 is saved in the "result". Then you add that result (which is 1) to the next element (1 + 2. This is 3). This will now be saved as the result. Keep going: 3 + 3 equals 6. And finally, 6 + 4 equals 10.

This is a simple and fairly easy to understand explanation:
Forget about the "initial value" as it is somewhat confusing at the beginning.
> [1,2,3,4].inject{|a,b| a+b}
=> 10
You can understand the above as: I am injecting an "adding machine" in between 1,2,3,4. Meaning, it is 1 ♫ 2 ♫ 3 ♫ 4 and ♫ is an adding machine, so it is the same as 1 + 2 + 3 + 4, and it is 10.
You can actually inject a + in between them:
> [1,2,3,4].inject(:+)
=> 10
and it is like, inject a + in between 1,2,3,4, making it 1 + 2 + 3 + 4 and it is 10. The :+ is Ruby's way of specifying + in the form of a symbol.
This is quite easy to understand and intuitive. And if you want to analyze how it works step by step, it is like: taking 1 and 2, and now add them, and when you have a result, store it first (which is 3), and now, next is the stored value 3 and the array element 3 going through the a + b process, which is 6, and now store this value, and now 6 and 4 go through the a + b process, and is 10. You are essentially doing
((1 + 2) + 3) + 4
and is 10. The "initial value" 0 is just a "base" to begin with. In many cases, you don't need it. Imagine if you need 1 * 2 * 3 * 4 and it is
[1,2,3,4].inject(:*)
=> 24
and it is done. You don't need an "initial value" of 1 to multiply the whole thing with 1. This time, it is doing
(((1 * 2) * 3) * 4)
and you get the same result as
1 * 2 * 3 * 4

This code doesn't allow the possibility of not passing a starting value, but may help explain what's going on.
def incomplete_inject(enumerable, result)
enumerable.each do |item|
result = yield(result, item)
end
result
end
incomplete_inject([1,2,3,4], 0) {|result, item| result + item} # => 10

One day, I was also banging my head against the default values in Ruby inject/reduce methods, so I've tried to visualize my issue:

Start here and then review all methods that take blocks.
http://ruby-doc.org/core-2.3.3/Enumerable.html#method-i-inject
Is it the block that confuses you or why you have a value in the method?
Good question though. What is the operator method there?
result.+
What does it start out as?
#inject(0)
Can we do this?
[1, 2, 3, 4].inject(0) { |result, element| result.+ element }
Does this work?
[1, 2, 3, 4].inject() { |result = 0, element| result.+ element }
You see I'm building on to the idea that it simply sums all the elements of the array and yields a number in the memo you see in the docs.
You can always do this
[1, 2, 3, 4].each { |element| p element }
to see the enumerable of the array get iterated through. That's the basic idea.
It's just that inject or reduce give you a memo or an accumulator that gets sent out.
We could try to get a result
[1, 2, 3, 4].each { |result = 0, element| result + element }
but nothing comes back so this just acts the same as before
[1, 2, 3, 4].each { |result = 0, element| p result + element }
in the element inspector block.

There is another form of .inject() method That is very helpful
[4,5].inject(&:+) That will add up all the element of the area

A common scenario that arises when using a collection of any sort, is to get perform a single type of operation with all the elements and collect the result.
For example, a sum(array) function might wish to add all the elements passed as the array and return the result.
A generalized abstraction of same functionality is provided in Ruby in the name of reduce (inject is an alias). That is, these methods iterate over a collection and accumulate the value of an operation on elements in a base value using an operator and return that base value in the end.
Let's take an example for better understanding.
>>> (5..10).inject(1) {|product, n| product * n }
=> 151200
In above example, we have the following elements: a base value 1, an enumerable (5..10), and a block with expressions instructing how to add the calculated value to base value (i.e., multiply the array element to product, where product is initialized with base value)
So the execution follows something like this:
# loop 1
n = 1
product = 1
return value = 1*1
# loop 2
n = 2
product = 1
return value = 1*2
n = 3
product = 2
return value = 2*3
..
As you can notice, the base value is continually updated as the expression loops through the element of container, thus returning the final value of base value as result.

Is the same as this:
[1,2,3,4].inject(:+)
=> 10

Related

Deeper explanation of reduce / inject method in ruby

I've been racking my brains around this for some time.
When using reduce - why is the first element returned without executing the operation defined in the block? Or am I missing a crucial point in how reduce works?
In the following example:
arr = [1, 3, 5]
arr.reduce {|sum, n| sum + (n * 3) }
#=> 25
I would have expected the result to be 27.
Since:
0 + (1 * 3) = 3
3 + (3 * 3) = 12
12 + (5 * 3) = 27
After some time playing around with it I figured out that in the first "tick" - the object from the array just get's added to the sum instead of being multiplied. So that the calculation is more like:
??? = 1
1 + (3 * 3) = 10
10 + (5 * 3) = 25
Could someone help me figure out where I've gotten off the path?
It's in the docs.
If you do not explicitly specify an initial value for memo, then the first element of collection is used as the initial value of memo.
I had a similar issue with the default values in Ruby inject/reduce methods, so I've tried to visualize it:
I thnk that the explanation is in the help o¡f the methos in this case:
[1] pry(main)> cd Array
[2] pry(Array):1> ? reduce
From: enum.c (C Method):
Owner: Enumerable
Visibility: public
Signature: reduce(*arg1)
Number of lines: 33
Combines all elements of enum by applying a binary
operation, specified by a block or a symbol that names a
method or operator.
The inject and reduce methods are aliases. There
is no performance benefit to either.
If you specify a block, then for each element in enum
the block is passed an accumulator value (memo) and the element.
If you specify a symbol instead, then each element in the collection
will be passed to the named method of memo.
In either case, the result becomes the new value for memo.
At the end of the iteration, the final value of memo is the
return value for the method.
If you do not explicitly specify an initial value for memo,
then the first element of collection is used as the initial value
of memo.
# Sum some numbers
(5..10).reduce(:+) #=> 45
# Same using a block and inject
(5..10).inject { |sum, n| sum + n } #=> 45
# Multiply some numbers
(5..10).reduce(1, :*) #=> 151200
# Same using a block
(5..10).inject(1) { |product, n| product * n } #=> 151200
# find the longest word
longest = %w{ cat sheep bear }.inject do |memo, word|
memo.length > word.length ? memo : word
end
longest #=> "sheep"
So you need to specify the first memo as 0, in your case is one:
[4] pry(Array):1> [1,3,5].reduce(0) {|sum, n| sum + (n * 3) }
=> 27

Check if the sum of two different numbers in an array equal a variable number?

In Ruby, I would like to take an array of numbers, select 2 different numbers, add those 2 numbers together and see weather there equal to a variable x.y'd a variable x. Here is the code I used
def arrayIsEqual? (numArray, x)
return true if numArray.sample + numArray.sample == x
return false if numArray.empty? || numArray.count == 1
end
for example
numArray = [4,2,7,5]
x = 11
arrayIsEqual (numArray, n) should return true, since 4 + 7 = n(11)
How do I get this to work?
I don't want it to be 2 random numbers, just any 2 different numbers that add up to n
It looks like you're trying to see if there are any two numbers in the array that add up to the specified value x. However, your code just picks two numbers at random and checks if those numbers add up.
Ruby has the Array#combination method, which generates all combinations of a given length:
def contains_pair_for_sum?(arr, n)
!!arr.uniq.combination(2).detect { |a, b| a + b == n }
end
A few things to note:
First, we named it according to Ruby conventions: each word is separated_by_underscores. The ? on the end means that the method is a predicate method and returns a true or false value.
Inside the method, a few things happen. Let's look at that line, piece by piece.
arr: We take the array that was passed in.
<...>.uniq: We only look at the unique elements (because the OP wants to pick two different numbers).
<...>.combination(2): We ask for all combinations from the array of length 2. If the array was [4, 5, 6], we'd get [[4, 5], [4, 6], [5, 6]].
<...>.detect { |a, b| a + b == n }: We look for the first combination that adds up to n. If we found one, that's the result of that method. Otherwise, we get nil.
!!<...>: Finally, we take the result we got from detect and negate it twice. The first negation produces a Boolean value (true if the value we got was nil, or false if it's anything else); the second negation produces a Boolean value that's identical to the truth value of the first negation. This is a Ruby idiom to coerce a result into being either true or false.
Let's see it in action:
array = [4, 5, 9, 7, 8]
contains_pair_for_sum?(array, 11)
# => true (because [4, 7] sums to 11)
contains_pair_for_sum?(array, 17)
# => true (because [9, 8] sums to 17)
contains_pair_for_sum?(array, 100)
# => false (no pair matched)
I understand that your question is "is there any pair of numbers in my array equals x", in which case this will do what you need:
def has_pair_equal?(num_array, x)
(0..num_array.length-1).any? do |i|
num_array[i+1..-1].any? { |n| n + num_array[i] == x }
end
end
This checks all sums of pairs of numbers in the array, and checks if their sum is x. sample randomly picks an item from the array, which means that what your code does is "return true sometimes if there is a pair of numbers in my array equals x"
def array_is_equal? (num_array, x)
equality = 0
num_array.each do |a|
equality += 1 if a == x
return true if equality == 2
end
return false
end
Use lowercase and underscores for variables in Ruby. The convention is different here than in some other languages.
One liner
x=[4,2,7,5]; x.each_with_index.any? {|y,i| x.each_with_index.any? {|z,j| unless i==j; z+y==11; end } }
And as a function
def pair_sum_match?(arr, x)
arr.each_with_index.any? do |y,i|
arr.each_with_index.any? do |z,j|
unless i==j
z+y==x
end
end
end
end
Updated: Added each_with_index to avoid self inclusion on checks. It's a lot longer now :-/
Just iterate over it once and use the target number to see if it matches. 100 times faster then most of the answers here
numbers = ( -10..10 ).to_a
numbers.unshift( numbers.first + -1 ) # if you do -20 or 20
numbers.push( numbers.last + 1 )
target = 5
searched = { }
matches = { }
numbers.each do |number|
if searched[ target - number + 1 ] == true
matches[ "#{ number }_plus_#{ target - number }" ] = target
end
searched[ number + 1 ] = true
end
ap matches

What's the easiest way to get Lisp-Style addition (+ *args) in Ruby?

So I really like this syntax in Lisp:
(+ 1 1 2 3 5 8 13)
=> 33
I want to add a list of items in Ruby and would like to approximate this as best as possible.
Right now, my best solution involves an array and the collect/map method.
So:
sum = 0; [1,1,2,3,5,8,13].collect { |n| sum += n }
BUT...
I would like to add methods to this which could return nil.
sum = 0; [1, booking_fee, 8,13].collect { |n| n = 0 if n.nil?; sum += n }
And it would be really nice to do this, where all of the lines in the middle refer to methods that may return nil, but I can't exactly build an array in this manner. This is just an idea of what I want my syntax to look like.
def total
Array.new do
booking_fee
rental_charges
internationalization_charges
discounts
wild_nights
end.collect { |n| n = 0 if n.nil?; sum += n }
end
Any suggestions before I try to hack away and effectuate Greenspun's Rule? (Programming is indeed a compulsion.
I really don't understand your question. If you want a method that works like + does in Lisp, i.e. takes an arbitrary number of arguments and is in prefix position rather than infix, that's trivial:
def plus(*nums)
nums.inject(:+)
end
plus 1, 1, 2, 3, 5, 8, 13 # => 33
If you want to get really fancy, you could override the unary prefix + operator for Arrays:
class Array
def +#
inject(:+)
end
end
+[1, 1, 2, 3, 5, 8, 13] # => 33
Please don't do that!
I don't see how the rest of your question is related in any way to a Lisp-style addition operation.
If you want to remove nils from an Array, there's Array#compact for that.
There is already a method inject for doing what you want.
Changing nil to a number without affecting a number is easy: use to_i (or to_f if you are dealing with float).
.
[
booking_fee,
rental_charges,
internationalization_charges,
discounts,
wild_nights,
].inject(0){|sum, item| sum + item.to_i}

Ruby : Finding lowest free ID in an ID array

I have an array with different IDs going from 1 to 4000. I need to add some elements in a database with an ID that would go in that array. Since the biggest ID possible is 4000 (which is not that much in my case), I'd like to be able to find the lowest unused ID possible I could use for my new element.
I would know how to do that in C++, but since I'm pretty new in Ruby, I'm asking for help. in C++, I would write a loop in which I would check if array[i] == array[i+1] - 1. If not the case, then the new id would be array[i] + 1.
I have just no idea how to write that in Ruby.
Using a range, you can find the first element that is not part of your array:
array = [1,2,3,5,6]
(1..4000).find { |i| !array.include?(i) }
# => 4
array = [1, 2, 3, 5, 6]
(1..4000).to_a.-(array).min
def first_unused_id(ids)
index = ids.each_index.find{|i| ids[i] + 1 != ids[i+1] }
ids[index] + 1
end
Some explanation:
each_index will transform the array into an Enumerator giving the arrays indices.
find will return the first element that returns true from the block passed to it.
how about this one:
(1..4000).find { |i| array[i-1] != i }
similar to Dylan's answer but in this case, it simply checks whether the [n-1]th member of the array is n. If not, that index is "open" and is returned. This solution only requires one check per index, not 4000...
so for
array = [1,2,3,5,6]
this would find that array[4-1] != 4 (because array[3] = 5) and return 4 as the first available id.
(this requires a sorted array of indices but that has been assumed so far)
array = [1, 2, 3, 5, 6]
def lowest_unused(ids)
ids.find { |e| ids.index(e) + 1 != e } - 1
end
p lowest_unused(array) # 4

How do I value from an array that returns objects at the beginning more often?

Given an array like [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], I want to get a random value that takes into consideration the position.
I want the likelihood of 1 popping up to be way bigger than 10.
Is something like this possible?
For the sake of simplicity let's assume an array arr = [x, y, z] from which we will be sampling values. We'd like to see following relative frequencies of x, y and z:
frequencies = [5, 2, 1]
Preprocess these frequencies to calculate margins for our subsequent dice roll:
thresholds = frequencies.clone
1.upto(frequencies.count - 1).each { |i| thresholds[i] += thresholds[i - 1] }
Let's sum them up.
max = frequencies.reduce :+
Now choose a random number
roll = 1 + rand max
index = thresholds.find_index { |x| roll <= x }
Return arr[index] as a result. To sum up:
def sample arr, frequencies
# assert arr.count == frequencies.count
thresholds = frequencies.clone
1.upto(frequencies.count - 1).each { |i| thresholds[i] += thresholds[i - 1] }
max = frequencies.reduce :+
roll = 1 + rand(max)
index = thresholds.find_index { |x| roll <= x }
arr[index]
end
Let's see how it works.
data = 80_000.times.map { sample [:x, :y, :z], [5, 2, 1] }
A histogram for data shows that sample works as we've intended.
def coin_toss( arr )
arr.detect{ rand(2) == 0 } || arr.last
end
a = (1..10).to_a
10.times{ print coin_toss( a ), ' ' } #=> 1 1 1 9 1 5 4 1 1 3
This takes the first element of the array, flips a coin, returns the element and stops if the coinflip is 'tails'; the same with the next element otherwise. If it is 'heads' all the way, return the last element.
A simple way to implement this with an logarithmic probabilistic of being selected is to simulate coin flips. Generate a random integer 0 and 1, the index to that array to choose is the number of consecutive 1s you get. With this method, the chance of selecting 2 is 1/2 as likely as 1, 3 is 1/4th as likely, etc. You can vary the probability slightly say by generating random numbers between 0 and 5 and count the number of consecutive rounds above 1, which makes each number in the array 4/5th as likely to appear as the one before.
A better and more general way to solve this problem is to use the alias method. See the answer to this question for more information:
Data structure for loaded dice?

Resources