This question already has answers here:
Get all keys in hash with same value
(3 answers)
Closed 5 years ago.
{"Amar"=>20,"Benton"=>14,"John"=>32,"Sunny"=>28,"Edward"=>19,"Leon"=>12,"Ram"=>19,"David"=>28}
the above hash has name and age ,i want to get the names which has same age in ruby
try this.
hash = {"name1"=>12, "name2"=>13, "name3"=>12}
groups = {}
hash.each do |k, v|
groups[v] = groups[v] || []
groups[v].push(k)
end
hash = {"Amar"=>20,"Benton"=>14,"John"=>32,"Sunny"=>28,"Edward"=>19,"Leon"=>12,"Ram"=>19,"David"=>28}
hash.keys.group_by { |k| hash[k] }.values.select { |g| g.size > 1 }
# => [["Sunny", "David"], ["Edward", "Ram"]]
Sunny and David have the same age, and so do Edward and Ram.
One solution is to create a hash with ages as the key and an array of names as the values:
names = {"Amar"=>20,
"Benton"=>14,
"John"=>32,
"Sunny"=>28,
"Edward"=>19,
"Leon"=>12,
"Ram"=>19,
"David"=>28}
ages = {}
names.each do |key, value|
ages[value] ||= []
ages[value] << key
end
puts ages
#=> {20=>["Amar"], 14=>["Benton"], 32=>["John"], 28=>["Sunny", "David"], 19=>["Edward", "Ram"], 12=>["Leon"]}
Note that if you want to get all the people who are 19 years old, you can just use ages[19].
For your hash
names_hash = {"Amar"=>20,"Benton"=>14,
"John"=>32,"Sunny"=>28,
"Edward"=>19,"Leon"=>12,
"Ram"=>19,"David"=>28}
You can always define a method which gives the desired names for an age
def names_for_age(age, hash = {})
hash.inject({}) do |container, (k,v)|
container[v] ||= []
container[v] << k
container
end[age]
end
So, now you can get the names as
names_for_age(10, names_hash)
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I want to pass hash:
filter_search = {age: 20, weight: 30, height: 30, salary: (100000..200000)}
to method
def search(array, filter)
array.select do |elem|
???????
end
end
filtered_array = search(some_array, filter_search)
How can I do this? Maybe I'm thinking in wrong way and there is another pattern to solve this?
Assuming the array parameter an array of objects that have the appropriate methods (age, weight, height, salary) and you want to return a filtered array of the ones that perfectly match your hash filter, something like this might work.
def search(array, filter)
array.select do |elem|
filter.all? do |key, value|
elem.send(key) == value
end
end
end
If you have hashes in your array instead of objects, you would use:
def search(array, filter)
array.select do |elem|
filter.all? do |key, value|
elem[key] == value
end
end
end
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
Is there anyway of grouping first common letters in an array of strings?
For example:
array = [ 'hello', 'hello you', 'people', 'finally', 'finland' ]
so when i do
array.group_by{ |string| some_logic_with_string }
The result should be,
{
'hello' => ['hello', 'hello you'],
'people' => ['people'],
'fin' => ['finally', 'finland']
}
NOTE: Some test cases are ambiguous and expectations conflict with other tests, you need to fix them.
I guess plain group_by may not work, a further processing is needed.
I have come up with below code that seems to work for all the given test cases in consistent manner.
I have left notes in the code to explain the logic. Only way to fully understand it will be to inspect value of h and see the flow for a simple test case.
def group_by_common_chars(array)
# We will iteratively group by as many time as there are characters
# in a largest possible key, which is max length of all strings
max_len = array.max_by {|i| i.size}.size
# First group by first character.
h = array.group_by{|i| i[0]}
# Now iterate remaining (max_len - 1) times
(1...max_len).each do |c|
# Let's perform a group by next set of starting characters.
t = h.map do |k,v|
h1 = v.group_by {|i| i[0..c]}
end.reduce(&:merge)
# We need to merge the previously generated hash
# with the hash generated in this iteration. Here things get tricky.
# If previously, we had
# {"a" => ["a"], "ab" => ["ab", "abc"]},
# and now, we have
# {"a"=>["a"], "ab"=>["ab"], "abc"=>["abc"]},
# We need to merge the two hashes such that we have
# {"a"=>["a"], "ab"=>["ab", "abc"], "abc"=>["abc"]}.
# Note that `Hash#merge`'s block is called only for common keys, so, "abc"
# will get merged, we can't do much about it now. We will process
# it later in the loop
h = h.merge(t) do |k, o, n|
if (o.size != n.size)
diff = [o,n].max - [o,n].min
if diff.size == 1 && t.value?(diff)
[o,n].max
else
[o,n].min
end
else
o
end
end
end
# Sort by key length, smallest in the beginning.
h = h.sort {|i,j| i.first.size <=> j.first.size }.to_h
# Get rid of those key-value pairs, where value is single element array
# and that single element is already part of another key-value pair, and
# that value array has more than one element. This step will allow us
# to get rid of key-value like "abc"=>["abc"] in the example discussed
# above.
h = h.tap do |h|
keys = h.keys
keys.each do |k|
v = h[k]
if (v.size == 1 &&
h.key?(v.first) &&
h.values.flatten.count(v.first) > 1) then
h.delete(k)
end
end
end
# Get rid of those keys whose value array consist of only elements that
# already part of some other key. Since, hash is ordered by key's string
# size, this process allows us to get rid of those keys which are smaller
# in length but consists of only elements that are present somewhere else
# with a key of larger length. For example, it lets us to get rid of
# "a"=>["aba", "abb", "aaa", "aab"] from a hash like
# {"a"=>["aba", "abb", "aaa", "aab"], "ab"=>["aba", "abb"], "aa"=>["aaa", "aab"]}
h.tap do |h|
keys = h.keys
keys.each do |k|
values = h[k]
other_values = h.values_at(*(h.keys-[k])).flatten
already_present = values.all? do |v|
other_values.include?(v)
end
h.delete(k) if already_present
end
end
end
Sample Run:
p group_by_common_chars ['hello', 'hello you', 'people', 'finally', 'finland']
#=> {"fin"=>["finally", "finland"], "hello"=>["hello", "hello you"], "people"=>["people"]}
p group_by_common_chars ['a', 'ab', 'abc']
#=> {"a"=>["a"], "ab"=>["ab", "abc"]}
p group_by_common_chars ['aba', 'abb', 'aaa', 'aab']
#=> {"ab"=>["aba", "abb"], "aa"=>["aaa", "aab"]}
p group_by_common_chars ["Why", "haven't", "you", "answered", "the", "above", "questions?", "Please", "do", "so."]
#=> {"a"=>["answered", "above"], "do"=>["do"], "Why"=>["Why"], "you"=>["you"], "so."=>["so."], "the"=>["the"], "Please"=>["Please"], "haven't"=>["haven't"], "questions?"=>["questions?"]}
Not sure, if you can sort by all common letters. But if you want to do sort only by first letter then here it is:
array = [ 'hello', 'hello you', 'people', 'finally', 'finland' ]
result = {}
array.each { |st| result[st[0]] = result.fetch(st[0], []) + [st] }
pp result
{"h"=>["hello", "hello you"], "p"=>["people"], "f"=>["finally", "finland"]}
Now result contains your desired hash.
Hmm, you're trying to do something that's pretty custom. I can think of two classical approaches that sort of do what you want: 1) Stemming and 2) Levenshtein Distance.
With stemming you're finding the root word to a longer word. Here's a gem for it.
Levenshtein is a famous algorithm which calculates the difference between two strings. There is a gem for it that runs pretty fast due to a native C extension.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I'm trying to remove key-value pairs from a hash whose value is less than the highest key-value pair's value in the hash. Example: If my hash is {:Jan => 3, :Feb =>4, :Mar =>4}, I'd want to remove the :Jan => 3 entry. I am attempting delete_if with a comparison to no avail.
def highestvalue(myhash)
myhash.delete_if { |k,v| v < v}
print myhash
end
months = {:Jan => 3, :Feb =>4, :Mar =>4}
highestvalue(months)
def highestvalue(myhash)
max = myhash.values.max
myhash.delete_if { |k, v| v < max }
end
I was helping with an answer in this question and it sparked a question of my own.
Pie is an object that has a pieces array made of of PiePiece objects.
Each PiePiece has a flavor attribute
How do I create a hash that looks like this:
# flavor => number of pieces
{
:cherry => 3
:apple => 1
:strawberry => 2
}
This works, but I think it could be improved
def inventory
hash = {}
pieces.each do |p|
hash[p.flavor] ||= 0
hash[p.flavor] += 1
end
hash
end
Any ideas?
def inventory
Hash[pieces.group_by(&:flavor).map{|f,p| [f, p.size]}]
end