convert hashed array to string - ruby

hash = { "d" => [11, 22], "f" => [33, 44, 55] }
is there an one liner to get a string like below:
d:11,d:22,f:33,f:44,f:55
thanks!
Great, thanks for the tip. Why this code doesn't work, only difference is I replaced vs.map with vs.each:
hash.map {|k,vs| vs.each {|v| "#{k}:#{v}"}}.join(",")
which returns "11,22,33,44,55"

Use two nested calls to map to get an array of arrays of "key:value" strings, and then use join to turn it into one comma-separated string:
hash.map {|k,vs| vs.map {|v| "#{k}:#{v}"}}.join(",")

hash.keys.map {|k| hash[k].map {|v| "#{k}:#{v}"}}.flatten.join(",")

Related

Convert a string to a path of keys in a hash

I have a string like string = "this_is_a_test" and a hash hash. How can I convert the string to a path of keys, so that it returns the value located at: hash['this']['is']['a']['test']?
I don't want to simply split the string into an array; I want to use the string as keys to access in a hash. The keys already exist in the hash.
Inject works nicely here:
hash = "this_is_a_test".split('_').reverse.inject("final value") { |h, s| {s => h} }
This returns:
{"this"=>{"is"=>{"a"=>{"test"=>"final value"}}}}
and:
hash['this']['is']['a']['test']
=> "final value"
The explanation here is that each iteration of inject returns a hash that contains the current string as a key, and the previous hash as a value, so each new key contains recursively all the hashes up to this point, including the deepest value that is passed as argument of inject.
This is why the array of keys needs to be reversed, because the hash is created from the inside-out.
edit: I believe I didn't understand the question correctly.
You actually meant to access an existing recursive hash.
Assuming the hash has been built using my previous method, accessing the innermost value can be achieved with inject too:
"this_is_a_test".split('_').inject(hash) { |h,v| h[v] }
=> "final value"
Also note that Ruby 2.3 implements the new Hash#dig method, which does exactly this, in a secure way:
path = "this_is_a_test".split('_')
hash.dig(*path) # => "final value"
could be something like this ?
keys = ["a", "b", "c"]
values = [1, 2, 3]
zipped = keys.zip(values)
=> [["a", 1], ["b", 2], ["c", 3]]
Hash[zipped]
=> {"a"=>1, "b"=>2, "c"=>3}
you are looking for String.split() function
var array = "this_is_a_test".split('_');

upcase array that has both strings and numbers

I am comparing large arrays to find missing elements. But one array will all be capitalized and the other is not. So I want to format the one array but am having issues. This is an example of the array I am trying to format.
array = [ 023, "Bac001", "abc123"]
Then I try to capitalize everything
array.map!(&:upcase)
but get undefined method 'upcase' for 023
is there a way around this?
I'd use Object#respond_to?:
def upcase_elements(ary)
ary.map { |e| e.respond_to?(:upcase) ? e.upcase : e }
end
upcase_elements([23, "BAC001", "ABC123"])
#=> [23, "BAC001", "ABC123"]
Checking if the receiver responds to a method is more flexible than checking its type:
upcase_elements([:foo, "bar"])
#=> [:FOO, "BAR"]
array.map! { |s| s.kind_of?(String) ? s.upcase : s }
This will not attempt to upcase any non-string element of the array. So it will work on arrays like:
array = [23, 1.27, "Bac001", "abc123", {:foo => 3}]
Yielding:
[23, 1.27, "BAC001", "ABC123", {:foo => 3}]

Ruby Hash - sort by value and print keys

This is my hash.
=> {"f11"=>1, "f12"=>3, "f13"=>3, "f07"=>5, "f10"=>1}
I'd like to sort by the values largest to smallest and then make an array out of the keys.
=> ["f07", "f12", "f13", "f11", "f10"]
Here's a one-liner for you (I love ruby!):
h.keys.sort {|a, b| h[b] <=> h[a]}
Hope that helps!
Hash has the Enumerable module mixed in which provides us with methods like sort and sort_by.In this situation we can use sort_by to get a collection by order of values.
h={"f11"=>1, "f12"=>3, "f13"=>3, "f07"=>5, "f10"=>1}
h.sort_by{ |key, value| -value }
=> [["f07", 5], ["f12", 3], ["f13", 3], ["f11", 1], ["f10", 1]]
Even shorter!:
h.keys.sort_by{|a| h[a]}.reverse
a = {"f11"=>1, "f12"=>3, "f13"=>3, "f07"=>5, "f10"=>1}
b = Hash[a.sort_by{|k,v| v}]
puts b.keys.reverse

Put the index first with each_with_index

I am using Array() with each_with_index to output a array with index but I want it to output
[[0,obj1],[1,obj2]....]
whereas each_with_index makes it output
[[obj1,0],[obj2,1]....]
Is there anyway this can be fixed easilly?
As been asked to show code.
Array(test.each_with_index)
Try adding .map { |x| x.reverse } after the each_with_index.
Use this:
[obj1, obj2, ..., objN].map.with_index{|a,i| [i,a] }
#=> [[0, obj1], [1, obj2], ..., [N-1, objN]]

How can I assign multiple values to a hash key?

For the sake of convenience I am trying to assign multiple values to a hash key in Ruby. Here's the code so far
myhash = { :name => ["Tom" , "Dick" , "Harry"] }
Looping through the hash gives a concatenated string of the 3 values
Output:
name : TomDickHarry
Required Output:
:name => "Tom" , :name => "Dick" , :name => "Harry"
What code must I write to get the required output?
myhash.each_pair {|k,v| v.each {|n| puts "#{k} => #{n}"}}
#name => Tom
#name => Dick
#name => Harry
The output format is not exactly what you need, but I think you get the idea.
The answers from Rohith and pierr are fine in this case. However, if this is something you're going to make extensive use of it's worth knowing that the data structure which behaves like a Hash but allows multiple values for a key is usually referred to as a multimap. There are a couple of implementations of this for Ruby including this one.
You've created a hash with the symbol name as the key and an array with three elements as the value, so you'll need to iterate through myhash[:name] to get the individual array elements.
re: the issue of iterating over selective keys. Try using reject with the condition inverted instead of using select.
e.g. given:
{:name=>["Tom", "Dick", "Harry"], :keep=>[4, 5, 6], :discard=>[1, 2, 3]}
where we want :name and :keep but not :discard
with select:
myhash.select { |k, v| [:name, :keep].include?(k) }
=> [[:name, ["Tom", "Dick", "Harry"]], [:keep, [4, 5, 6]]]
The result is a list of pairs.
but with reject:
myhash.reject { |k, v| ![:name, :keep].include?(k) }
=> {:name=>["Tom", "Dick", "Harry"], :keep=>[4, 5, 6]}
The result is a Hash with only the entries you want.
This can then be combined with pierr's answer:
hash_to_use = myhash.reject { |k, v| ![:name, :keep].include?(k) }
hash_to_use.each_pair {|k,v| v.each {|n| puts "#{k} => #{n}"}}

Resources