In Ruby how do I sort a hash by its key values in alphabetical order? - ruby

Suppose I have a hash,
{"c": 1, "b": 2, "a": 3}
How do I sort the hash so the elements are in order of the key value?

myh = {"c" => 1, "b" => 2, "a" => 3}
myh.sort
=> [["a", 3], ["b", 2], ["c", 1]]

{"c" => 1, "b" => 2, "a" => 3}.sort.to_h

Related

Sort array by other array

I have two arrays:
a = [ 1, 0, 2, 1, 0]
b = ['a', 'b', 'c', 'd', 'e']
I want to order the b array according to a's elements values.
I can make this by merging the two arrays into a Hash and the order by key:
h = Hash[b.zip a]
=> {"a"=>1, "b"=>0, "c"=>2, "d"=>1, "e"=>0}
h2 = Hash[h.sort_by{|k, v| v}]
=> {"b"=>0, "e"=>0, "a"=>1, "d"=>1, "c"=>2}
array = h2.keys
=> ["b", "e", "a", "d", "c"]
Where there is a tie the order may be chosen arbitrary.
Is there a way (maybe more compact), I can achieve this without using the hash.
a.zip(b).sort.map(&:last)
In parts:
p a.zip(b) # => [[1, "a"], [0, "b"], [2, "c"], [1, "d"], [0, "e"]]
p a.zip(b).sort # => [[0, "b"], [0, "e"], [1, "a"], [1, "d"], [2, "c"]]
p a.zip(b).sort.map(&:last) # => ["b", "e", "a", "d", "c"]
a = [ 1, 0, 2, 1, 0]
b = ['a', 'b', 'c', 'd', 'e']
p b.sort_by.each_with_index{|el,i| a[i]}
# => ["b", "e", "a", "d", "c"]

Creating a method to modify elements in an array in Ruby with 2 arguments, one of them being the original array

I would like to create a method, mod_method(array, n) , where array is an array and n is a number. mod_method should take number n and add it to all internal numbers in array and return that new array.
For example, using array = ["I", "have", 3, "to", 4, "hours"], how would I find mod_method(array, 1) such that
mod_method(array,1)
=> ["I", "have", 4, "to", 5, "hours"]
I'm a noob and was only able to do this using the already defined array and number (let's use 1), as such:
array = ["I", "have", 3, "to", 4, "hours"]
=>[[0] "I",
[1] "have",
[2] 3,
[3] "to",
[4] 4,
[5] "hours"]
numbers = array.values_at(2, 4)
=> [
[0] 3,
[1] 4
mod = numbers.map{|x| x + 1}
=> [
[0] 4,
[1] 5]
new_array = ["I", "have", mod[0], "to", mod[1], "hours"]
=> ["I", "have", 4, "to", 5, "hours"]
I have no idea how to do it with undefined arguments for the mod_method.
Write the method as
def mod_method(array, n)
array.map { |i| i.is_a?(Fixnum) ? (i + n) : i }
end
array = ["I", "have", 3, "to", 4, "hours"]
mod_method(array, 1) # => ["I", "have", 4, "to", 5, "hours"]
If your array contains both Fixnum and Float instances, and you want to add 1 with either of those instances. Then use the below method :-
def mod_method(array, n)
array.map { |i| i.kind_of?(Numeric) ? (i + n) : i }
end
array = ["I", "have", 3.2, "to", 4, "hours"]
mod_method(array, 1) # => ["I", "have", 4.2, "to", 5, "hours"]
Here is what I would do.
def mod_method(array,n)
array.map do |e|
e.is_a?(Integer) ? e + n : e
end
end

Merge two hashes with alternation in Ruby (2.x.x)

I have two hashes:
h1 = {'a' => 33, 'b' => 4, 'c' => 6}
h2 = {'d' => 10, 'e' => 1, 'f' => 12}
Now they should be merged into one, with alternation, so the final hash should be like:
{'a' => 33, 'd' => 10, 'b' => 4, 'e' = 1, 'c' => 6, 'f' => 12}
What's the best way to do that. Probably a single liner?
Thanks!
Here is my try
Hash[*[h1.to_a, h2.to_a].transpose.flatten]
# => {"a"=>33, "d"=>10, "b"=>4, "e"=>1, "c"=>6, "f"=>12}
# or
Hash[*h1.to_a.zip(h2.to_a).flatten]
# => {"a"=>33, "d"=>10, "b"=>4, "e"=>1, "c"=>6, "f"=>12}
Even with more STARS. :-)
Hash[*[*h1, *h2].transpose.flatten]
# => {"a"=>"b", "c"=>"d", "e"=>"f", 33=>4, 6=>10, 1=>12}
No stars!
h1 = {'a' => 33, 'b' => 4, 'c' => 6}
h2 = {'d' => 10, 'e' => 1, 'f' => 12}
h1.to_a.zip(h2.to_a).flatten(1).to_h
#=> {"a"=>33, "d"=>10, "b"=>4, "e"=>1, "c"=>6, "f"=>12}
For Ruby versions < 2.0:
Hash[h1.to_a.zip(h2.to_a).flatten(1)]
Note Array#transpose and Enumerable#zip are always interchangeable when manipulating arrays.
For Ruby versions < 1.9, the ordering of key/value pairs in hashes was not specified. For those versions, the closest you could come to answering your question would be to provide a desired ordering of keys:
keys_in_order = ['a', 'd', 'b', 'e', 'c', 'f']
retrieve the associated values:
values = h1.merge(h2).values_at(*keys_in_order)
#=> [33, 10, 4, 1, 6, 12]
and pair these with zip:
keys_in_order.zip(values)
#=> [["a", 33], ["d", 10], ["b", 4], ["e", 1], ["c", 6], ["f", 12]]

Joining multiple ordered arrays in Ruby

Lets say I have this:
a = [1, 2, 3, 4, 5]
b = ['a', 'b', 'c', 'd', 'e']
c = ['ABC', 'DEF', 'GHI', 'JKL', 'MNO']
And I want this:
d = [[1, 'a', 'ABC'], [2, 'b', 'DEF'], ...]
How can I accomplish this in Ruby?
I tried with .zip
r = []
r.zip(a, b, c)
puts r
But didn't work.
You need to do as below :-
a = [1, 2, 3, 4, 5]
b = ['a', 'b', 'c', 'd', 'e']
c = ['ABC', 'DEF', 'GHI', 'JKL', 'MNO']
a.zip(b,c)
# => [[1, "a", "ABC"], [2, "b", "DEF"], [3, "c", "GHI"], [4, "d", "JKL"], [5, "e", "MNO"]]
One thing to remember here - Array#zip returns an array of size, equal to the size of the receiver array object.
# returns an array of size 2, as the same as receiver array size.
[1,2].zip([1,5,7]) # => [[1, 1], [2, 5]]
# below returns empty array, as the receiver array object is also empty.
[].zip([1,2,3,4,5]) # => []
For the same reason as I explained above r.zip(a, b, c) returns [].
[a,b,c].reduce(:zip).map(&:flatten)
d = [a,b,c].transpose
[[1, "a", "ABC"], [2, "b", "DEF"], [3, "c", "GHI"], [4, "d", "JKL"], [5, "e", "MNO"]]

How can I push keys to an unsorted array?

I'm trying to create an array of the keys of an ordered hash. I want them to be listed in the same order in both the array and the hash. I have this hash.
h = { "a" => 3, "b" => 1, "c" = 4, "d" = 2 }
What I want is this array.
arr = ["b", "d", "a", "c"]
I have
h.sort_by { |k, v| v}
h.keys
but that returns the keys in alphabetical order. What can I do to keep them in the order of the sorted hash?
h.sort_by{|k,v| v} will give you [["b", 1], ["d", 2], ["a", 3], ["c", 4]], then use .map to get the key.
h.sort_by{|k,v| v}.map &:first
h = { "a" => 3, "b" => 1, "c" => 4, "d" => 2 }
p h.sort_by(&:last).map(&:first) #=> ["b", "d", "a", "c"]
You may try this also,
h = { "a" => 3, "b" => 1, "c" => 4, "d" => 2 }
Hash[h.sort_by{|k,v| v}].keys
#=> ["b", "d", "a", "c"]
This code
h.sort_by { |k,v| v}
h.keys
doesn't work because the sort_by method doesn't sort the original array, it returns a new sorted array, where each value is a (key, value) pair from the original hash:
[["b", 1], ["d", 2], ["a", 3], ["c", 4]]
If you're using Ruby 2.1.1, you can then just call to_h on the array, which will re-map the key/value pairs back into a hash:
h.sort_by { |k, v| v}.to_h.keys

Resources