Create hash with keys from array and a standard value - ruby

I have an array like this:
['a', 'b', 'c']
What is the simplest way to turn it into:
{'a' => true, 'b' => true, 'c' => true}
true is just a standard value that values should hold.

How about below ?
2.1.0 :001 > ['a', 'b', 'c'].each_with_object(true).to_h
=> {"a"=>true, "b"=>true, "c"=>true}

Try:
Hash[ary.map {|k| [k, true]}]
Since Ruby 2.0 you can use to_h method:
ary.map {|k| [k, true]}.to_h

Depending on your specific needs, maybe you do not actually need to initialize the values. You could simply create a Hash with a default value of true this way:
h = Hash.new(true)
#=> {}
Then, when you try to access a key that was not present before:
h['a']
#=> true
h['b']
#=> true
Pros: less memory used, faster to initialize.
Cons: does not actually store keys so the hash will be empty until some other code stores values in it. This will only be a problem if your program relies on reading the keys from the hash or wants to iterate over the hash.

['a', 'b', 'c'].each_with_object({}) { |key, hash| hash[key] = true }

Another one
> Hash[arr.zip Array.new(arr.size, true)]
# => {"a"=>true, "b"=>true, "c"=>true}

You can also use Array#product:
['a', 'b', 'c'].product([true]).to_h
#=> {"a"=>true, "b"=>true, "c"=>true}

Following code will do this:
hash = {}
['a', 'b', 'c'].each{|i| hash[i] = true}
Hope this helps :)

If you switch to Python, it's this easy:
>>> l = ['a', 'b', 'c']
>>> d = dict.fromkeys(l, True)
>>> d
{'a': True, 'c': True, 'b': True}

Related

How to check if a key exists in an array of arrays?

Is there a straightforward way to do something like the following without excessive looping?
myArray = [["a","b"],["c","d"],["e","f"]]
if myArray.includes?("c")
...
I know this works fine if it's just a normal array of chars... but I would like something equally as elegant for an array of an array of chars (bonus points for helping convert this to an array of tuples).
If you only need a true/false answer you can flatten the array and call include on that:
>> myArray.flatten.include?("c")
=> true
You can use assoc:
my_array = [['a', 'b'], ['c', 'd'], ['e', 'f']]
if my_array.assoc('c')
# ...
It actually returns the whole subarray:
my_array.assoc('c') #=> ["c", "d"]
or nil if there is no match:
my_array.assoc('g') #=> nil
There's also rassoc to search for the second element:
my_array.rassoc('d') #=> ["c", "d"]
my_array = [["a","b"],["c","d"],["e","f"]]
p my_hash = my_array.to_h # => {"a"=>"b", "c"=>"d", "e"=>"f"}
p my_hash.key?("c") # => true
You can use Array#any?
myArray = [["a","b"],["c","d"],["e","f"]]
if myArray.any? { |x| x.includes?("c") }
# some code here
The find_index method works well for this:
myArray = [["a","b"],["c","d"],["e","f"]]
puts "found!" if myArray.find_index {|a| a[0] == "c" }
The return value is the array index of the pair or nil if the pair is not found.
You can capture the pair's value (or nil if not found) this way:
myArray.find_index {|a| a[0] == "c" } || [nil, nil])[1]
# => "d"

Combining two arrays into a hash

I'm trying to combine two arrays into a hash.
#sample_array = ["one", "Two", "Three"]
#timesheet_id_array = ["96", "97", "98"]
I want to output the results into a hash called #hash_array. Is there a simple way to combine the two in a code block so that if you call puts at the end it looks like this in the console
{"one" => "96", "Two" => "97", "Three" => "98"}
I think this could be done in one or two lines of code.
try this
keys = [1, 2, 3]
values = ['a', 'b', 'c']
Hash[keys.zip(values)]
thanks
#hash_array = {}
#sample_array.each_with_index do |value, index|
#hash_array[value] = #timesheet_id_array[index]
end
Imho that looks best:
[:a,:b,:c].zip([1,2,3]).to_h
# {:a=>1, :b=>2, :c=>3}
Dr. Nic suggests 2 options explained well at http://drnicwilliams.com/2006/10/03/zip-vs-transpose/
#hash_array = {}
0.upto(#sample_array.length - 1) do |index|
#hash_array[#sample_array[index]] = #timesheet_id_array[index]
end
puts #hash_array.inspect

Ruby array to hash: each element the key and derive value from it

I have an array of strings, and want to make a hash out of it. Each element of the array will be the key, and I want to make the value being computed from that key. Is there a Ruby way of doing this?
For example:
['a','b'] to convert to {'a'=>'A','b'=>'B'}
You can:
a = ['a', 'b']
Hash[a.map {|v| [v,v.upcase]}]
%w{a b c}.reduce({}){|a,v| a[v] = v.upcase; a}
Ruby's each_with_object method is a neat way of doing what you want
['a', 'b'].each_with_object({}) { |k, h| h[k] = k.upcase }
Here's another way:
a.zip(a.map(&:upcase)).to_h
#=>{"a"=>"A", "b"=>"B"}
Which ever way you look at it you will need to iterate the initial array. Here's another way :
a = ['a', 'b', 'c']
h = Hash[a.collect {|v| [v, v.upcase]}]
#=> {"a"=>"A", "b"=>"B", "c"=>"C"}
Here's a naive and simple solution that converts the current character to a symbol to be used as the key. And just for fun it capitalizes the value. :)
h = Hash.new
['a', 'b'].each {|a| h[a.to_sym] = a.upcase}
puts h
# => {:a=>"A", :b=>"B"}
From Rails 6.x, you can use Enumerable#index_with:
irb(main):002:0> ['a', 'b'].index_with {|s| s.upcase}
=> {"a"=>"A", "b"=>"B"}
Pass a block to .to_h
[ 'a', 'b' ].to_h{ |element| [ element, element.upcase ] }
#=> {"a"=>"A", "b"=>"B"}
Thanks to #SMAG for the refactor suggestion!
Not sure if this is the real Ruby way but should be close enough:
hash = {}
['a', 'b'].each do |x|
hash[x] = x.upcase
end
p hash # prints {"a"=>"A", "b"=>"B"}
As a function we would have this:
def theFunk(array)
hash = {}
array.each do |x|
hash[x] = x.upcase
end
hash
end
p theFunk ['a', 'b', 'c'] # prints {"a"=>"A", "b"=>"B", "c"=>"C"}

Conditional key/value in a ruby hash

Is there a nice (one line) way of writing a hash in ruby with some entry only there if a condition is fulfilled? I thought of
{:a => 'a', :b => ('b' if condition)}
But that leaves :b == nil if the condition is not fulfilled. I realize this could be done easily in two lines or so, but it would be much nicer in one line (e.g. when passing the hash to a function).
Am I missing (yet) another one of ruby's amazing features here? ;)
UPDATE Ruby 2.4+
Since ruby 2.4.0, you can use the compact method:
{ a: 'a', b: ('b' if cond) }.compact
Original answer (Ruby 1.9.2)
You could first create the hash with key => nil for when the condition is not met, and then delete those pairs where the value is nil. For example:
{ :a => 'a', :b => ('b' if cond) }.delete_if{ |k,v| v.nil? }
yields, for cond == true:
{:b=>"b", :a=>"a"}
and for cond == false
{:a=>"a"}
UPDATE for ruby 1.9.3
This is equivalent - a bit more concise and in ruby 1.9.3 notation:
{ a: 'a', b: ('b' if cond) }.reject{ |k,v| v.nil? }
From Ruby 1.9+, if you want to build a hash based on conditionals you can use tap, which is my new favourite thing. This breaks it onto multiple lines but is more readable IMHO:
{}.tap do |my_hash|
my_hash[:a] = 'a'
my_hash[:b] = 'b' if condition
end
>= Ruby 2.4:
{a: 'asd', b: nil}.compact
=> {:a=>"asd"}
Interested in seeing other answers, but this is the best I can think up of for a one-liner (I'm also notoriously bad at one-liners :P)
{:a => 'a'}.merge( condition ? {:b => 'b'} : {} )
There's a lot of clever solutions in here, but IMO the simplest and therefore best approach is
hash = { a: 'a', b: 'b' }
hash[:c] = 'c' if condition
It goes against the OP's request of doing it in two lines, but really so do the other answers that only appear to be one-liners. Let's face it, this is the most trivial solution and it's easy to read.
In Ruby 2.0 there is a double-splat operator (**) for hashes (and keyword parameters) by analogy to the old splat operator (*) for arrays (and positional parameters). So you could say:
{a: 'b', **(condition ? {b: 'b'} : {})}
Hash[:a, 'a', *([:b, 'b'] if condition1), *([:c, 'c'] if condition2)]
This relies on the fact that *nil expands to vacuity in ruby 1.9. In ruby 1.8, you might need to do:
Hash[:a, 'a', *(condition1 ? [:b, 'b'] : []), *(condition2 ? [:c, 'c'] : [])]
or
Hash[:a, 'a', *([:b, 'b'] if condition1).to_a, *([:c, 'c'] if condition2).to_a]
If you have multiple conditions and logic that others will need to understand later then I suggest this is not a good candidate for a 1 liner. It would make more sense to properly create your hash based on the required logic.
This one is nice for multiple conditionals.
(
hash = {:a => 'a'}.tap {|h|
h.store( *[(:b if condition_b), 'b'] )
h.store( *[(:c if condition_c), 'c'] )
}
).delete(nil)
Note that I chose nil as the "garbage" key, which gets deleted when you're done. If you ever need to store a real value with a nil key, just change the store conditionals to something like:
(condition_b ? :b : garbage_key)
then delete(garbage_key) at the end.
This solution will also keep existing nil values intact, e.g. if you had :a => nil in the original hash, it won't be deleted.
My one-liner solution:
{:a => 'a'}.tap { |h| h.merge!(:b => 'b') if condition }
hash, hash_new = {:a => ['a', true], :b => ['b', false]}, {}
hash.each_pair{|k,v| hash_new[k] = v[1] ? v : nil }
puts hash_new
eval("{:a => 'a' #{', :b => \'b\'' if condition }}")
or even
eval("{#{[":a => 'a'", (":b=>'b'" if ax)].compact.join(',')}}")
for more simple add conditions

What is the meaning of grep on a Hash?

{'a' => 'b'}.grep /a/
=> []
>> {'a' => 'b'}.grep /b/
=> []
It doesn't seem to match the keys or values. Does it do something I'm not discerning?
grep is defined on Enumerable, i.e. it is a generic method that doesn't know anything about Hashes. It operates on whatever the elements of the Enumerable are. Ruby doesn't have a type for key-value-pairs, it simply represents Hash entries as two-element arrays where the first element is the key and the second element is the value.
grep uses the === method to filter out elements. And since neither
/a/ === ['a', 'b']
nor
/b/ === ['a', 'b']
are true, you always get an empty array as response.
Try this:
def (t = Object.new).===(other)
true
end
{'a' => 'b'}.grep t
# => [['a', 'b']]
Here you can see how grep works with Hashes.

Resources