From an array of hashes:
response = [
{"label"=>"cat", "name"=>"kitty", "id"=>189955},
{"label" => "dog", "name"=>"rex", "id" => 550081}
]
is there a way to write something like:
response.name.kitty
to retrieve the hash that contains this value:
{"label"=>"cat", "name"=>"kitty", "id"=>189955}
You can do this -
response.select{|x| x["name"] == "kitty"}.first
Use a Proc
response = [{"label"=>"cat", "name"=>"kitty", "id"=>189955},
{"label" => "dog", "name"=>"rex", "id" => 550081}]
finder = Proc.new {|k, v| response.find {|r| r[k] == v} }
Then
finder.call('name', 'rex')
# => {"label"=>"dog", "name"=>"rex", "id"=>550081}
finder.call('label', 'cat')
# => {"label"=>"cat", "name"=>"kitty", "id"=>189955}
You can also pass multiple conditions if required like this:
response = [
{"label"=>"cat", "name"=>"kitty", "id"=>189955},
{"label"=>"cat", "name"=>"kitty", "id"=>189956},
{"label"=>"cat", "name"=>"kitty", "id"=>189957},
{"label"=>"cat", "name"=>"meow", "id"=>189957},
{"label" => "dog", "name"=>"rex", "id" => 550081},
{"label" => "dog", "name"=>"tommy", "id" => 550082},
{"label" => "dog", "name"=>"rex", "id" => 550083}
]
> response.select{|h| h["label"] == "cat" && h["name"] == "kitty" && h["id"] == 189955}
=> [{"label"=>"cat", "name"=>"kitty", "id"=>189955}] # returns array of selected hashes
> response.find{|h| h["label"] == "cat" && h["name"] == "kitty" && h["id"] == 189955}
=> {"label"=>"cat", "name"=>"kitty", "id"=>189955} # returns first match element
if you're using Rails - just use .pluck
array_of_hashes = [
{ name: "Kate", city: "Minsk", country: "Belarus", id: 1 },
{ name: "Mike", city: "New York", country: "USA", id: 2 },
{ name: "Aleh", city: "Warsaw", country: "Poland", id: 3},
]
>> array_of_hashes.pluck(:name)
>>
>> [ "Kate", "Mike", "Aleh" ]
Related
Here the array of hashes:
array = [
{:ID => "aaa", :phase => "alpha", :quantity => 80},
{:ID => "aaa", :phase => "beta", :quantity => 160}
]
I'm trying to transform the value of :phase into a key and to assign its value taking the value of :quantity, as follow:
array = [
{:ID => "aaa", :"alpha" => 80},
{:ID => "aaa", :"beta" => 160}
]
Thanks!
I would do it like this:
array = [
{:ID => "aaa", :phase => "alpha", :quantity => 80},
{:ID => "aaa", :phase => "beta", :quantity => 160}
]
array.map { |hash| { :ID => hash[:ID], hash[:phase].to_sym => hash[:quantity] } }
#=> [{:ID=>"aaa", :alpha=>80}, {:ID=>"aaa", :beta=>160}]
You can do it like this:
array.map do |hash|
new_key = hash.delete(:phase)
quantity = hash.delete(:quantity)
hash[new_key] = quantity
hash
end
In an array of hash how to delete an element with particular value for a key?
For example:
array = [ {"lang"=> 'Ruby', "is_using"=> "Yes"}, { "lang"=> "Go", "is_using" => "No"}, {"lang"=> "Rust", "is_using"=> "No"} ]
I need to write a minimal and efficient ruby script which deletes all the elements from the array which has "No" as a value for the key "is_using".
Use Array#delete_if:
array = [ {"lang"=> 'Ruby', "is_using"=> "Yes"}, { "lang"=> "Go", "is_using" => "No"}, {"lang"=> "Rust", "is_using"=> "No"} ]
array.delete_if { |hash| hash['is_using'] == 'No' }
#=> [{ "lang" => "Ruby", "is_using" => "Yes" }]
If you don't want to mutate the original array, then you could use reject:
array = [{ "lang"=> 'Ruby', "is_using"=> "Yes" },
{ "lang"=> "Go", "is_using" => "No" },
{ "lang"=> "Rust", "is_using"=> "No" }]
array.reject { |h| h["is_using"].eql?('Yes') }
# [{"lang"=>"Go", "is_using"=>"No"}, {"lang"=>"Rust", "is_using"=>"No"}]
I have an array of arrays:
data = [
["Smith", "Bob", "Male"],
["Jim", "Tim", "Male"],
["Welch", "Anne", "Female"]
]
How would I convert it to look like:
data = [
{:first_name => "Smith", :last_name => "Bob", :gender => "Male"},
{:first_name => "Jim", :last_name => "Tim", :gender => "Male"},
{:first_name => "Welch", :last_name => "Anne", :gender => "Female"}
]
You can do something like this:
fields = [:first_name, :last_name, :gender]
data.map {|row| fields.zip(row).to_h }
#=> [{:first_name=>"Smith", :last_name=>"Bob", :gender=>"Male"}, {:first_name=>"Jim", :last_name=>"Tim", :gender=>"Male"}, {:first_name=>"Welch", :last_name=>"Anne", :gender=>"Female"}]
Keep in mind that this will only work if the elements are in the same order as the fields.
Also you could use Struct:
presenter = Struct.new(:first_name, :last_name, :gender)
data.map { |e| presenter.new(*e).to_h }
#=> [{:first_name=>"Smith", :last_name=>"Bob", :gender=>"Male"},
# {:first_name=>"Jim", :last_name=>"Tim", :gender=>"Male"},
# {:first_name=>"Welch", :last_name=>"Anne", :gender=>"Female"}]
fields = [:first_name, :last_name, :gender]
data.map{|d| Hash[fields.zip(d)]}
I have an array
animals = [
[{"name" => "Alex", "spices" => "dog", "vname" => "colour", "value" => "black"},
{"name" => "Alf", "spices" => "dog", "vname" => "colour", "value" => "white"},
{"name" => "Sonia", "spices" => "dog", "vname" => "colour", "value" => "white"}],
[{"name" => "Alex", "spices" => "dog", "vname" => "health", "value" => "80"},
{"name" => "Alf", "spices" => "dog", "vname" => "health", "value" => "98"}],
[{"name" => "Alex", "spices" => "dog", "vname" => "age", "value" => "12"}]
]
Every animal (Alex, Alf and Sonia) is described by colour, health and age (vname values), but Alf does not have his hash with age in third subarray and Sonia does not have her hashes with health (second subarray) and age (third subarray). I want to check if any subarray does not have "vname" pair for some dog and if doesn't to add hash like this
{"name" => "Alf", "spices" => "dog", "vname" => "age", "value" => "unknown"}
to get an array
animals = [
[{"name" => "Alex", "spices" => "dog", "vname" => "colour", "value" => "black"},
{"name" => "Alf", "spices" => "dog", "vname" => "colour", "value" => "white"},
{"name" => "Sonia", "spices" => "dog", "vname" => "colour", "value" => "white"}],
[{"name" => "Alex", "spices" => "dog", "vname" => "health", "value" => "80"},
{"name" => "Alf", "spices" => "dog", "vname" => "health", "value" => "98"},
{"name" => "Sonia", "spices" => "dog", "vname" => "health", "value" => "unknown"}],
[{"name" => "Alex", "spices" => "dog", "vname" => "age", "value" => "12"},
{"name" => "Alf", "spices" => "dog", "vname" => "age", "value" => "unknown"},
{"name" => "Sonia", "spices" => "dog", "vname" => "age", "value" => "unknown"}]
]
Can You help me with this?
Umm. Set the names in an Array. Loop through your animals array and for each of the array inside, check if has hash for all animal names. Add the default hash for those that are missing.
animal_names = ["Alex", "Alf", "Sonia"]
animals.each do |animals_by_vname|
vname = animals_by_vname.first["vname"]
names_present = animals_by_vname.map {|i| i["name"]}
names_missing = animal_names - names_present
names_missing.each do |name|
animals_by_vname << {
"name" => name,
"spices" => "dog",
"vname" => vname,
"value" => "unknown"
}
end
end
puts animals # should be you wanted it.
That solves your problem.
However, I honestly believe, the data structure needs to be optimised. Maybe have a hash of arrays with animal names as keys. Like:
{
"Alex": { health: "good" }
"Alf": { age: 10, health: "good" }
}
Your data format is very hard to work with.
You could define an Animal class, keep an Animal.all hash and write your data in this structure:
data = [
[{ 'name' => 'Alex', 'spices' => 'dog', 'vname' => 'colour', 'value' => 'black' },
{ 'name' => 'Alf', 'spices' => 'dog', 'vname' => 'colour', 'value' => 'white' },
{ 'name' => 'Sonia', 'spices' => 'dog', 'vname' => 'colour', 'value' => 'white' }],
[{ 'name' => 'Alex', 'spices' => 'dog', 'vname' => 'health', 'value' => '80' },
{ 'name' => 'Alf', 'spices' => 'dog', 'vname' => 'health', 'value' => '98' }],
[{ 'name' => 'Alex', 'spices' => 'dog', 'vname' => 'age', 'value' => '12' }]
]
class Animal
attr_accessor :name, :species, :health, :age, :colour
#all = {}
class << self
attr_reader :all
def find_or_create_by_name(params)
all[params['name']] ||= Animal.new(params)
end
end
def initialize(params)
#name = params['name']
#species = params['spices']
end
def to_h
{
name: name,
species: species,
age: age || 'unknown',
colour: colour || 'unknown',
health: health || 'unknown'
}
end
def to_s
to_h.to_s
end
alias inspect to_s
end
data.each do |info|
info.each do |params|
animal = Animal.find_or_create_by_name(params)
animal.instance_variable_set("##{params['vname']}", params['value'])
end
end
require 'pp'
pp Animal.all
# {"Alex"=>
# {:name=>"Alex", :species=>"dog", :age=>"12", :colour=>"black", :health=>"80"},
# "Alf"=>
# {:name=>"Alf", :species=>"dog", :age=>"unknown", :colour=>"white", :health=>"98"},
# "Sonia"=>
# {:name=>"Sonia", :species=>"dog", :age=>"unknown", :colour=>"white", :health=>"unknown"}}
I have an array A that looks like this:
A = [ { "id" => "1234", "name" => "audi", "isCool" => false },
{ "id" => "5678", "name" => "acura", "isCool" => false },
{ "id" => "9101112", "name" => "bentley", "isCool" => true },
{ "id" => "13141516", "name" => "rollsroyce", "isCool" => true },
{ "id" => "17181920", "name" => "toyota", "isCool" => true } ]
and I have an array B that looks like this:
B = ["1234", "13141516”]
I am trying to select only elements from array A that match array A's ids with Array Bs elements.
So the returned results I would like is:
C = [ { "id" => "1234", "name" => "audi", "isCool" => false },
{ "id" => "13141516", "name" => "rollsroyce", "isCool" => true } ]
Is there an easy way to go about this?
I have currently tried this but obviously not a good idea:
a.select {|x| x['id'] == B.first || B.last}
But obviously this is not dynamic, because what if I had 3 or 4 elements in array B.
A.select { |x| B.include?(x['id']) }