Looking at a hash as an array? - arrays

I found this example of using #any? on a hash a bit tricky:
"With a Hash, you can use these in two ways. Either with one argument that is a 2 element array of the key-value pair. candidate[0] is the key and candidate[1] is its value.
{:locke => 4, :hugo => 8}.any? { |candidate| candidate[1] > 4 }
This returns true because the value of the second candidate :hugo is greater than 4."
Could anyone point me someplace that explains what happened here? I couldn't find a relevant question on SO. Thanks a lot in advance.

If you print candidate it will become easy to understand:
{:locke => 4, :hugo => 8}.any? { |candidate| puts candidate.to_s }
# [:locke, 4]
# [:hugo, 8]
The any? method is treating each key-value pair of the hash as an a two-element array, which means the hash will be treated as an array of arrays.
The block passed to any? (i.e., { |candidate| candidate[1] > 4 }) returns true if any of the the second elements (i.e., 4 and 8) is ever > 4 and false otherwise. 8 > 4, so the result is true.
From the official docs, the any? method:
Passes each element of the collection to the given block. The method
returns true if the block ever returns a value other than false or
nil. If the block is not given, Ruby adds an implicit block of { |obj|
obj } that will cause any? to return true if at least one of the
collection members is not false or nil.

What Hash#any? does is yield arrays of two elements to a given block and return true if the evaluation of the block returned something truthy (not false or nil) and false otherwise.
As for why you get two values if you pass a block with two arguments - this is called unpacking.
def foo
yield [42, 6 * 9]
end
# only one argument, array is not unpacked
foo { |numbers| p numbers } # prints [42, 54]
# two arguments, the array is being unpacked
foo { |x, y| p x, y } # prints 42 \n 54

Related

Rails- is there a method that is essentially `map.find` for arrays?

Looking for a method that will iterate through a list and return the first transformed value.
Essentially:
[1, 2, 3, 4].magic { |i|
puts "Checking #{i}"
i ** 2 if i > 2
}
Checking 1
Checking 2
Checking 3
#=> 9
The goal here being that it works like find and stops iterating through the list after getting the first return. (Notice it never checks 4) but also returns the value from the block. (Returns 9 instead of 3)
The issue here is that the block is performing some complex logic, so I don't want to map over the entire array, but I also want to use the value of said logic.
You can break the loop with a desired return value. Is this what you are looking for?
array = [1, 2, 3, 4]
array.map { |element| break element ** 2 if element > 2 }
# returns 9

In Ruby, during iteration of an array, how do I send multiple array elements as values for one specific hash key?

I know how to iterate through an array and I know how to create hash keys and values. I do not know how to create an array for the value and pass it multiple elements. My desired value for hash below is:
{'abc' => [1, 2, 3] , 'def' => [4,5,6,7]}
How would I achieve this hash, while iterating through array a and b below using each?
a = [1,2,3,4,5,6,7]
c = [1,2,3]
b = ['abc', 'def']
hash = {}
From your guidelines given in the comment:
While iterating through array a, if the element of iteration is included in array c, it is passed to the array value within key 'abc'. Otherwise, it is passed to other array value in key 'def'
You can do this:
hash = {}
hash['abc'] = a.select { |x| c.include?(x) }
hash['def'] = a.reject{ |x| c.include?(x) }
See Enumerable#select and Enumerable#reject. Also can take a look at Enumerable#partition which would be another good choice here, where you want to split an array into two arrays based on some condition:
in_a, not_in_a = a.partition { |x| c.include?(x) }
hash = { 'abc' => in_a, 'def' => not_in_a }
You can also do it with regular each if these fancy enumerable methods are bit too much for you:
hash = { 'abc' => [], 'def' => [] }
a.each do |x|
if c.include?(x)
hash['abc'].push(x)
else
hash['def'].push(x)
end
end
Unfortunately this question turned out not to be as interesting as I was hoping. I was hoping that the problem was this:
Knowing the hash key and a value, how can I make sure the key's value is an array and that the given value is appended to that?
For instance, start with h being {}. I have a key name :k and a value 1. I want h[:k], if it doesn't already exist, to be [1]. But if it does already exist, then it's an array and I want to append 1 to that array; for instance, if h[:k] is already [3,2], now it should be [3,2,1].
I can think of various ways to ensure that, but one possibility is this:
(hash[key] ||= []) << value
To see that this works, let's make it a method:
def add_to_hash_array_value(hash:, key:, value:)
(hash[key] ||= []) << value
end
Now I'll just call that a bunch of times:
h = {}
add_to_hash_array_value(hash:h, key:"abc", value:1)
add_to_hash_array_value(hash:h, key:"abc", value:2)
add_to_hash_array_value(hash:h, key:"def", value:4)
add_to_hash_array_value(hash:h, key:"def", value:5)
add_to_hash_array_value(hash:h, key:"abc", value:3)
puts h #=> {"abc"=>[1, 2, 3], "def"=>[4, 5]}
We got the right answer.
This is nice because suppose I have some way of knowing, given a value, what key it should be appended to. I can just repeatedly apply that decision-making process.
However, the trouble with trying to apply that to the original question is that the original question seems not to know exactly how to decide, given a value, what key it should be appended to.

Ruby - compare two arrays for index matches and with the remainder if included

Working on a project to recreate a game Mastermind. I need to compare two arrays, and running into some struggles.
I need to output two integers for the flow of the game to work,
the first integer is the number of correct choices where the index matches. The code I have for this appears to be working
pairs = #code.zip(guess)
correct_position_count = pairs.select { |pair| pair[0] == pair[1] }.count
Where pairs is equal to a 4 element array and the guess is also a 4 element array
The second part I am having a bit of trouble with on how to do the comparison and return an array. The integer should represent where the two arrays index don't match (the above code block but !=) and confirm whether the guess array excluding any exact index matches has any elements included with the code array once again excluding the exact index matches.
Any help would be greatly appreciated!
I am not completely sure to understand your problem but if I understood well, you've two arrays, solution with the solution and guess with the current guess of the player.
Now, let's assume that the solution is 1234 and that the guess is 3335.
solution = [1, 2, 3, 4]
guess = [3, 3, 3, 5]
an element by element comparison produces an array of booleans.
diff = guess.map.with_index { |x,i| x == solution[i] }
# = [false, false, true, false]
Now, you can easily compute the number of good digits diff.count true and the number of wrong digits diff.count false. And, in case you need the index of the false and/or true values you can do
diff.each_index.select { |i| diff[i] } # indexes with true
# = [2]
diff.each_index.select { |i| !diff[i] } # indexes with false
# = [0, 1, 3]
You can count all digit matches ignoring their positions and then subtract exact matches.
pairs = #code.zip(guess)
correct_position_count = pairs.select { |pair| pair[0] == pair[1]}.count
any_position_count = 0
code_digits = #code.clone # protect #code from modifying
guess.each do |digit|
if code_digits.include?(digit)
code_digits.delete_at(code_digits.find_index(digit)) # delete the found digit not to count it more than once
any_position_count += 1
end
end
inexact_position_count = any_position_count - correct_position_count
puts "The first value: #{correct_position_count}"
puts "The second value: #{inexact_position_count}"

How to understand Ruby's .each and .map

I am having trouble understanding the differences between map and each, and where and when to use them.
I read "What does map do?" and "Ruby Iterators" but wanted some clarification.
If I have:
z = [1,2,3].map {|x| x + 1}
map takes each element in the array z and adds one to each element, however it does not mutate the original array unless I add !.
On the other hand:
y = [1,2,3].each {|x| x + 1}
returns [1,2,3]. This is confusing to me since:
names = ['danil', 'edmund']
names.each { |name| puts name + ' is a programmer' }
returns:
Danil is a programmer
Edmund is a programmer
What is exactly going on in my second example that isn't allowing each array element to be increased by 1, while in the last example a string is being attached to everything in the array?
All credits go to Speransky Danil, whom I took these examples off of.
The map method takes an enum given some block, and iterates through it doing some logic. In your case the logic is x+1. As you say it will not mutate anything unless you use !.
each is simply returning the array that is being called.
Let's take an example of:
names = ["bob"]
If we do:
names.each{|names| names + "somestring"}
the output is still ["bob"]. The reason your second example is different is due to the puts.
As an exercise try doing:
y = [1,2,3].each {|x| puts x + 1}
You will get:
2
3
4
[1,2,3]
tl;dr: I use map if I want to change my collection, apply a transformation on it, end up with something different. I use each if I just need to visit every element in a collection.
Key point is: you should use map if you want to apply a transformation on an array (an enumerable in reality, but let's keep it simple at the beginning). Otherwise, if you don't need to change your array, you can simply use each.
Note that in the code below you are not mutating the array but you are simply take advantage of the local string to print each string with a suffix.
names = ['danil', 'edmund']
names.each { |name| puts name + ' is a programmer' }
Obviously, you could do the same with map but in this case you don't need it and you have to use an each too to print every element. The code would be
names = ['danil', 'edmund']
names.map! { |name| name + ' is a programmer' }
# or names = names.map { |name| name + ' is a programmer' }
name.each { |name| puts name }
This is covered in Ruby's documentation in multiple places but the easiest to understand for your use is in the Array documentation for each:
each { |item| block } → ary
each → Enumerator
Calls the given block once for each element in self, passing that element as a parameter. Returns the array itself.
If no block is given, an Enumerator is returned.
a = [ "a", "b", "c" ]
a.each {|x| print x, " -- " }
produces:
a -- b -- c --
Note that it says "Returns the array itself."
Compare that to map:
map { |item| block } → new_ary
map → Enumerator
Invokes the given block once for each element of self.
Creates a new array containing the values returned by the block.
See also Enumerable#collect.
If no block is given, an Enumerator is returned instead.
a = [ "a", "b", "c", "d" ]
a.collect { |x| x + "!" } #=> ["a!", "b!", "c!", "d!"]
a.map.with_index { |x, i| x * i } #=> ["", "b", "cc", "ddd"]
a #=> ["a", "b", "c", "d"]
Note that it says "Creates a new array containing the values returned by the block."
This example should help knowing the above:
foo = [1,2,3]
foo.each { |i| puts i + 1 } # => [1, 2, 3]
foo.map { |i| i + 1 } # => [2, 3, 4]
# >> 2
# >> 3
# >> 4
where # => is the return value of the block and # >> is the captured STDOUT from puts.
And, knowing all that, use each when you want to display elements in the array or extract and reuse those elements as parameters or to build things. Use map when you want to change the elements of the array into something else.
The difference is that each is performing an action on each element in the array, returning the original array. The action performed possibly mutated the element.
Whereas map is performing an action on each element in the array and returning its result as an array.
In the first case, map:
z = [1,2,3].map {|x| x + 1}
will take each element in the given array and perform the operation in the block and return a new array, so here it returns [2,3,4].
.each executes the block for each of the elements in the array, and it will not change anything in the array, so here it performs x + 1, but it doesn't store it anywhere, hence in the second case it just returns the array.
Now in the third example you posted, you are printing output in the block itself. Again, there is no change in the array itself.

select method on array providing different results

The following are identical:
First method:
puts [1,2,3,4,5,6,6,6,6].select {|number| number == 6 }
Output:
6
6
6
6
Second method:
array = [1,2,3,4,5,6,6,6,6]
array.select do |number|
puts number == 6
end
Output:
false
false
false
false
false
true
true
true
true
Why don't I get the same result for each? How do I go about getting the same result? Please explain what is going on.
Described in the ruby doc,
select → an_enumerator
Returns an array containing all elements of enum for which the given
block returns a true value.
[1,2,3,4,5,6,6,6,6].select {|number| number == 6 }
returns as intended (i.e, return an array where the number == 6)
[6, 6, 6, 6]
In the second method, you're simply outputting the result of the comparison, which will result in a boolean.
Regarding the output, the first method puts the selected array whereas the second method puts each evaluation of the condition (regardless of whether the condition is met).
Regarding the selected array, the block in the first method returns the evaluation of number == 6, which leads to the selected array [6, 6, 6, 6], whereas the block in the second method returns the evaluation of puts, which is nil, which leads to the selected array [].
Regarding the return value of the entire code, the first method returns the evaluation of puts, which is nil, whereas the second method returns the selected array [].

Resources