I have a hash and an array. I want to check whether an array element is in the hash as a key, and if not, delete the key from the hash.
RegionScoreHash={"A"=>1, "B"=>0, "C"=>0, "D"=>1, "E"=>0, "F"=>0, "G"=>0}
RegionsArray=["B", "C", "D", "E", "F"]
Result Required: Hash with elements present in array (A and G regions removed)
ResultHash={"B"=>0, "C"=>0, "D"=>1, "E"=>0, "F"=>0}
Use Array's delete_if method to modify the hash in place.
RegionScoreHash.delete_if { |k| !RegionsArray.include?(k) }
or use something like select if you want a new result.
result = RegionScoreHash.select { |k| RegionsArray.include?(k) }
Deleting is inefficient.
ResultHash = RegionsArray.inject({}){|h, k| h[k] = RegionScoreHash[k]; h}
Try this
RegionScoreHash={"A"=>1, "B"=>0, "C"=>0, "D"=>1, "E"=>0, "F"=>0, "G"=>0}
RegionsArray=["B", "C", "D", "E", "F"]
RegionScoreHash.delete_if {|a| !RegionsArray.include?(a)}
As advice the ruby way should be region_score_hash instead RegionScoreHash.
Since you've tagged ruby-on-rails, let's assume you have ActiveSupport's extensions to Enumerable, which allows use of exclude?
Combine it with Hash's delete_if method
RegionScoreHash.delete_if { |k, _v| RegionsArray.exclude?(k) }
and you should get back a hash with only keys that are present in RegionsArray.
Related
I've an array contains hashes, I want to filter few parameters from the hash and insert the filtered data in another array but am not succeed below is the sample data I've used
a = Array.new
a = [
{"name"=>"hello", "age"=>"12", "sex"=> "M", "city"=>"Chennai"},
{"name"=>"name2", "age"=>"26", "sex"=> "M", "city"=>"Banglore"}
]
line_item = Array.new
hash_data = {}
a.each do |datas|
hash_data[:name] = datas["name"]
hash_data[:age] = datas["age"]
line_item << hash_data
end
I am getting this result:
[
{:name=>"name2", :age=>"26"},
{:name=>"name2", :age=>"26"}
]
But am expecting this:
[
{:name=>"hello", :age=>"12"},
{:name=>"name2", :age=>"26"}
]
Somebody please help to sort out this, Thanks in advance
Defining the hash outside the loop means that you keep adding the same hash object again (while overwriting its previous values). Instead, create a fresh hash within the loop:
line_items = []
a.each do |datas|
hash_data = {}
hash_data[:name] = datas["name"]
hash_data[:age] = datas["age"]
line_items << hash_data
end
The code looks a bit unidiomatic. Let's refactor it.
We can set the keys right within the hash literal:
line_items = []
a.each do |datas|
hash_data = { name: datas["name"], age: datas["age"] }
line_items << hash_data
end
We can get rid of the hash_data variable:
line_items = []
a.each do |datas|
line_items << { name: datas["name"], age: datas["age"] }
end
And we can use map to directly transform the array:
line_items = a.map { |h| { name: h["name"], age: h["age"] } }
#=> [{:name=>"hello", :age=>"12"}, {:name=>"name2", :age=>"26"}]
You can get the expected result with a combination of map and slice
a = [
{"name"=>"hello", "age"=>"12", "sex"=> "M", "city"=>"Chennai"},
{"name"=>"name2", "age"=>"26", "sex"=> "M", "city"=>"Banglore"}
]
a.map{ |e| e.slice("name", "age") }
#=> [{"name"=>"hello", "age"=>"12"}, {"name"=>"name2", "age"=>"26"}]
map: Returns Array containing the values returned by block
slice: Returns Hash including only the specified keys
In your loop you are essentially populating line_item with hash_data twice. This is the same object however. You can remedy this by using .dup.
a.each do |datas|
hash_data[:name]=datas["name"]
hash_data[:age]=datas["age"]
line_item << hash_data.dup # <- here
end
irb(main):044:0> line_item
=> [{:name=>"hello", :age=>"12"}, {:name=>"name2", :age=>"26"}]
Edit: I prefer rado's suggestion of moving your definition of hash_data inside the loop over using .dup. It solves the problem more than treating the symptom.
I think a lot of people are over complicating this.
You can achieve this using the following:
a.map { |hash| hash.select { |key, _value| key == 'name' || key == 'age' } }
If you want to return an array, you should nearly always be using map, and select simply selects the key - value pairs that match the criteria.
If you're set on having symbols as the keys, you can call symbolize_keys on the result.
I'll expand the code so it's a little more readable, but the one liner above works perfectly:
a.map do |hash|
hash.select do |key, _value|
key == 'name' || key == 'age'
end
end
On the first line hash_data[:name]=datas["name"] you are setting the key of the hash. That's why when the loop iterate again, it is overriding the value and after that push the new result to the hash.
One solution with reusing this code is just to put the hash_data = {} on the first line of your loop. This way you will have a brand new hash to work with on every iteration.
Also I would recommend you to read the docs about the Hash module. You will find more useful methods there.
If you want for all keys you can do this
array = [{"name"=>"hello", "age"=>"12", "sex"=> "M", "city"=>"Chennai"}, {"name"=>"name2", "age"=>"26""sex"=> "M", "city"=>"Banglore"}]
new_array = array.map{|b| b.inject({}){|array_obj,(k,v)| array_obj[k.to_sym] = v; array_obj}}
Ref: inject
Happy Coding
I have to iterate on array in my rails controller but it only returns the last value of it:
array = ["a", "b", "c"]
array.each do |arr|
#arry = arr
end
#arry gives me "c" but I want it to give me a b c
So, when I add a API method in the each iteration, it only gives me a result for the "c" value but I want a result for all of them.
FYI: when I iterate this array in my view, everything works
array.each do |el|
#arr = el
end
Every loop you are saving el as #arr (overriding previous value)so after full each you have last el. You can do it like this if you want to do something with each element.
#arr = array.map { |el| el }
or just
#arr = array
Use map enumerator:
#arry = array.map { |arr| arr }
https://ruby-doc.org/core-2.2.0/Array.html#method-i-map
I am trying to take input as a string.
Then I need to find all the possible combination and distinct combination but I am unable to do so.
input = "aabb"
Output I need to print all Combination =
'a','a','b','b','aa','ab','bb','aab','abb','aabb'
Now Distinct combination
'a','b','aa','ab','bb','aab','abb','aabb'
Then I need to count the letters and do a summation
'a','a','b','b','aa','ab','bb','aab','abb','aabb'
For this
result = 1+1+1+1+2+2+2+3+3+4
Similarly for the other combination I need to find summation.
You can use Array#combination.
To get all combinations:
input = "aabb"
res = []
input.size.times { |n| res << input.chars.combination(n+1).map { |a| a.join } }
res.flatten
#=> ["a", "a", "b", "b", "aa", "ab", "ab", "ab", "ab", "bb", "aab", "aab", "abb", "abb", "aabb"]
distinct combinations:
res.flatten.uniq
#=> ["a", "b", "aa", "ab", "bb", "aab", "abb", "aabb"]
to count the letters and do a summation:
res.flatten.uniq.map(&:size)
#=> [1, 1, 2, 2, 2, 3, 3, 4]
res.flatten.uniq.map(&:size).reduce(:+)
# => 18
To get all the substrings of your input (or more generally to get all subsequences of an Enumerable) you can use something like this:
def subsequences(e)
a = e.to_a
indices = (0..a.length - 1).to_a
indices.product(indices)
.reject { |i, j| i > j }
.map { |i, j| a[i..j] }
end
You would use that on your string like this: subsequences(input.chars).map(&:join). The chars and join are only necessary because Strings are not Enumerable, but the subsequences function does not really need that. You can just take out the first line and it should still work for strings (anything that has a "slicing" subscript operator, really ...).
Note also that this is not the only way to do this. The basic problem here is to iterate over all ordered pairs of indices of a sequence. You could also do that with basic loops. I just happen to find the cartesian product method very elegant. ;)
Once you have your first list in a variable, say list, the second task is as easy as list.uniq, and the third one is solved by
list.map(&:size).reduce(:+)
For an array like this:
a = [{a:'a',b:'3'},{a:'b',b:'2'},{a:'c',b:'1'}]
I would like to return an array containing values for :a keys, so:
['a', 'b', 'c']
That can be done using:
a.map{|x|x[:a]}
I wonder if there is a native method in Rails or Ruby to do it like this?
a.something :a
You can do it yourself:
class Array
def get_values(key)
self.map{|x| x[key]}
end
end
Then you can do this:
a.get_values :a
#=> ["a", "b", "c"]
More than you need in this case, but from How to merge array of hashes to get hash of arrays of values you can get them all at once:
merged = a.inject{ |h1,h2| h1.merge(h2){ |_,v1,v2| [*v1,*v2] } }
p merged[:a] #=> ["a", "b", "c"]
p merged[:b] #=> ["3", "2", "1"]
Also, if you use something like Struct or OpenStruct for your values instead of hashes—or any object that allows you to get the "a" values as a method that does not require parameters—you can use the Symbol#to_proc convenience for your map:
AB = Struct.new(:a,:b)
all = [ AB.new('a','3'), AB.new('b','2'), AB.new('c','1') ]
#=> [#<AB a="a", b="3">, #<AB a="b", b="2">, #<AB a="c", b="1">]
all.map(&:a) #=> ["a", "b", "c"]
all.map(&:b) #=> ["3", "2", "1"]
This question already has answers here:
Why are exclamation marks used in Ruby methods?
(12 answers)
Closed 8 years ago.
From Ruby's official documentation:
sort → new_ary sort { |a, b| block } → new_ary Returns a new array
created by sorting self.
Comparisons for the sort will be done using the <=> operator or using
an optional code block.
The block must implement a comparison between a and b, and return -1,
when a follows b, 0 when a and b are equivalent, or +1 if b follows a.
See also Enumerable#sort_by.
a = [ "d", "a", "e", "c", "b" ]
a.sort #=> ["a", "b", "c", "d", "e"]
a.sort { |x,y| y <=> x } #=> ["e", "d", "c", "b", "a"]
sort! → ary click to toggle source sort! { |a, b| block } → ary Sorts
self in place.
Comparisons for the sort will be done using the <=> operator or using
an optional code block.
The block must implement a comparison between a and b, and return -1,
when a follows b, 0 when a and b are equivalent, or +1 if b follows a.
See also Enumerable#sort_by.
a = [ "d", "a", "e", "c", "b" ]
a.sort! #=> ["a", "b", "c", "d", "e"]
a.sort! { |x,y| y <=> x } #=> ["e", "d", "c", "b", "a"]
The result seems the same, so what's the difference?
sort will not modify the original array whereas sort! will
('!' is the bang method in ruby, it will replace the existing value)
For example:
a = [4,3,2,5,1]
a.sort # => [1,2,3,4,5]
a is still [4,3,2,5,1]
where as
a = [4,3,2,5,1]
a.sort! # => [1,2,3,4,5]
a is now [1,2,3,4,5]
In rails ! used to apply changes and update its calling object means
a.sort will only return sorted array but a.sort! will return sorted array and also save new sort result in a variable.
'!' is the bang method in ruby, it will replace the existing value
ex: .sort is a normal sorting method in ruby
.sort! its a bang method in ruby its override the existing value.