I am working on the Leetcode Two Sums problem: "Given an array of integers, return indices of the two numbers such that they add up to a specific target.". This is what I have:
def two_sum(nums, target)
hash = {}
nums.each_with_index do |num, index|
diff = target - num
if hash[diff]
return [hash[diff],index]
else
hash[num] = index
end
end
end
The code works, however, I'm not too sure why this works.
So I understand that in the each statement it goes through the numbers and it finds the difference. For example,
nums = [4,2,5,1]
target = 6
On the first loop, the difference is 6-2 = 4. But the hash is obviously empty so it will register num as a key, with the current index as the value. Thus the hash is,
hash = {
4: 0
}
On the second loop, the difference is 6-4 = 2. hash[4] is nil so it will add the current num and index to the dictionary.
hash = {
4: 0
2: 1
}
Like so, wouldn't this keep adding the nums to the hash, because at least in this case there aren't matching key value pairs?
Maybe I am overcomplicating things. If someone could eli5, I would greatly appreciate it. Thank you!
The trick is that we add the value to the hash using the number as the key:
hash[num] = index
but extract it using the diff as the key:
if hash[diff]
So if you have as input:
nums = [4,2,5,1]
target = 6
Then on first step, the difference is 6 - 4 = 2, there's no key 2 (diff) in the map, and we add the key 4 (number) to the map.
On the second step, the difference is 6 - 2 = 4, and there's already a key 4 (diff) in the map, so we return the value.
ary = [1, 4, 6, 9]
(0...ary.size).bsearch { |i|
ary[i] - 1
} # => nil
1 - ary[i] # => 0
When the code is written in a form ary[i] - 1 which doesn't work as expected.
What I am trying to do is to find the index of the number 1 in the array.
But 1 - ary[i] can return the number's index correctly. Why doesn't ary[i] - 1 work?
Array#bsearch is meant to perform binary search to find an element that meets certain criteria. As per documentation, if you return numeric values from the block, the find-any mode type of search is used.
The search starts at center of the sorted array - and if block returns negative value, it continues search in first half, and if block returns positive value, it continues the search in second half of the array.
In your case when you use ary[i] - 1, the value returned by block is always positive and search continues recursively on second half of the array - and never finds the value 1.
Here is the code with some debug statements:
ary = [1, 4, 6, 9]
p (0...ary.size).bsearch { |i|
puts "Elem: #{ary[i]} Index: #{i}"
ary[i] - 1
}
Output:
Elem: 4 Index: 1
Elem: 6 Index: 2
Elem: 9 Index: 3
nil
[Finished in 0.4s]
Array#bsearch returns an element of the array, not the index of a matching element.
You might want to use Array#index instead.
If you want to find the index of the element instead of the element itself, you need to use Array#bsearch_index. Note: this method was introduced in Ruby 2.3, which at the time of this writing has not been released yet (it will be released on Christmas 2015).
The feature request for Array#bsearch_index contains a comment by Yusuke Endoh showing how to implement Array#bsearch_index (and in fact Array#bsearch as well) based on Range#bsearch:
class Array
def bsearch_index(&blk)
return enum_for(__method__) unless blk
(0...size).bsearch {|i| yield self[i] }
end
end
When either running Ruby 2.3 or using the above monkey patch, you can then do:
ary.bsearch_index(&1.method(:-))
in order to find the index of the 1 element in your array.
The reason why it doesn't work with
ary.bsearch_index {|el | el - 1 }
is simple: the block violates the contract of bsearch_index (and also bsearch since they are the same). The block needs to return a positive number for indices left of the one you are searching for, a negative number for indices right of the one you are searching for, and 0 for indices within the range you are searching for. Your block does the opposite.
Here's what I thought:
def appendUnique(a,x)
for i in 0 .. a.size-1 do
if a[i]=x then
a==a
else
a=a+x
end
p(a)
end
end
appendUnique([-1,5,3],4)
Compare each member of a with x, if a equals x, return a, else return a+x. Why doesn't this work? It just replaces all array members with 4s...
I want this: result [-1, 5, 3, 4] from the above since 4 isn't in the array and [-1, 5, 3] from appendUnique([-1,5,3],5).
There are several issues with your code:
in Ruby we usually use each instead of for to iterate collections
a[i] = x is an assignment, you want a[i] == x
a == a just returns true
a + x concatenates two arrays, but x is not an array
I would simply use Array#include? to check if the item is present:
def appendUnique(array, item)
if array.include? item
array
else
array + [item]
end
end
If you want an array with unique elements you can use Set class
It just replaces all array members with 4s...
a[i]=x is an assignment rather than comparison. Running this in a loop, as you do, would set every element of a to x (which is 4).
The rest of the code needs quite a lot of work too. For example: you should only be appending to a after you've run the loop and have established that x isn't in the array.
This is my problem I have met in my assignment.
Array A has two elements: array B and array C.
Array B has two elements: array D and array E
At some point, array X just contains two elements: string a and string b.
I don't know how to determine how deep array A is. For example:
arrA = [
[
[1,2]
]
]
I have tested by: A[0][0][0] == nil which returns false. Moreover, A[0][0]..[0] == nil always returns false. So, I cannot do this way to know how deep array A is.
If this is not what you're looking for, it should be a good starting point:
def depth (a)
return 0 unless a.is_a?(Array)
return 1 + depth(a[0])
end
> depth(arrA)
=> 3
Please note that this only measures the depth of the first branch.
My solution which goes below answers the maximum depth of any array:
Example: for arr=[ [[1],[2,3]], [[[ 3,4 ]]] ], the maximum depth of arr is 4 for 3,4.
Aprroach - flatten by one level and compare
b, depth = arr.dup, 1
until b==arr.flatten
depth+=1
b=b.flatten(1)
end
puts "Array depth: #{depth}" #=> 4
Hope it answers your question.
A simple pure functional recursive solution:
def depth(xs, n=0)
return case
when xs.class != Array
n
when xs == []
n + 1
else
xs.collect{|x| depth x, n+1}.max
end
end
Examples:
depth([]) == 1
depth([['a']])) == 2
depth([1, 2, 3, 4, [1, 2, 3, [[2, 2],[]], 4, 5, 6, 7], 5, 5, [[[[[3, 4]]]]], [[[[[[[[[1, 2]]]]]]]]]]) == 10
Here's a one-liner similar to kiddorails' solution extracted into a method:
def depth(array)
array.to_a == array.flatten(1) ? 1 : depth(array.flatten(1)) + 1
end
It will flatten the array 1 dimension at the time until it can't flatten anymore, while counting the dimensions.
Why is this better than other solutions out there?
doesn't require modification to native classes (avoid that if possible)
doesn't use metaprogramming (is_a?, send, respond_to?, etc.)
fairly easy to read
works on hashes as well (notice array.to_a)
actually works (unlike only checking the first branch, and other silly stuff)
Also one line code if you want to use
def depth (a)
a.to_s.count("[")
end
[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