Reputation: 53
I have a hash:
hash = {"a" => 1, "b" =>2, "c" => 3, "d" => 4}
And I have an array:
array = ["b", "a", "d"]
I would like to create a new array that is made up of the original hash values that correspond with original hash keys that are also found in the original array while maintaining the sequence of the original array. The desired array being:
desired_array = [2, 1, 3]
The idea here is to take the word "bad", assign numbers to the alphabet, and then make an array of the numbers that correspond with "b" "a" and "d" in that order.
Upvotes: 0
Views: 428
Reputation: 97
Enumerable methods map, each works perfect
desired_array = array.map { |k| hash[k] }
or
desired_array = array.each { |k| hash[k] }
Upvotes: 0
Reputation: 58
Since your question is a little unclear I'm assuming you want desired_array to be an array (you say you want a new array and finish the sentence off with new hash). Also in your example I'm assuming you want desired_array to be [2, 1, 4] for ['b', 'a', 'd'] and not [2, 1, 3] for ['b', 'a', 'c'].
You should just you the Enumerable#map method to create a array that will map the first array to the your desired array like so:
desired_array = array.map { |k| hash[k] }
You should familiarize yourself with the Enumerable#map method, it's quite the handy method. From the rubydocs for the method: Returns a new array with the results of running block once for every element in enum. So in this case we are iterating through array and invoking hash[k] to select the value from the hash and creating a new array with values selected by the hash. Since iteration is in order, you will maintain the original sequence.
Upvotes: 1
Reputation: 61885
I would use Enumerable#map
followed by Enumerable#sort_by
, for example:
hash = {"d" => 4, "b" =>2, "c" => 3, "a" => 1}
order = ["b", "a", "d"]
# For each key in order, create a [key, value] pair from the hash.
# (Doing it this way instead of filtering the hash.to_a is O(n) vs O(n^2) without
# an additional hash-probe mapping. It also feels more natural.)
selected_pairs = order.map {|v| [v, hash[v]]}
# For each pair create a surrogate ordering based on the `order`-index
# (The surrogate value is only computed once, not each sort-compare step.
# This is, however, an O(n^2) operation on-top of the sort.)
sorted = selected_pairs.sort_by {|p| order.find_index(p[0]) }
p sorted
# sorted =>
# [["b", 2], ["a", 1], ["d", 4]]
I've not turned the result back into a Hash, because I am of the belief that hashes should not be treated as having any sort of order, except for debugging aids. (Do keep in mind that Ruby 2 hashes are ordered-by-insertion.)
Upvotes: 0