How to use .uniq with hashes for unique pairs? - ruby

Lets say I have an array with several hashes of emails and names. For example I have something like this:
foo = [{id: 1, name: 'Eric Cartman', email: 'eric#southpark.com'},
{id: 2, name: 'Eric Cartman', email: 'cartmanfamily#gmail.com'},
{id: 3, name: "Cartman's mom", email: 'cartmanfamily#gmail.com'},
{id: 4, name: 'Eric Cartman', email: 'eric#southpark.com'}]
How can I use .uniq to return unique values based on the combination of name and email? For example I want to return something like this:
[{id: 1, name: 'Eric Cartman', email: 'eric#southpark.com'},
{id: 2, name: 'Eric Cartman', email: 'cartmanfamily#gmail.com'},
{id: 3, name: "Cartman's mom", email: 'cartmanfamily#gmail.com'}]

foo.uniq should work just fine.
Since
{name: "cartman", email: "cartman#sp.com"} == {name: "cartman", email: "cartman#sp.com"} # => True
{name: "stan", email: "stan#sp.com"} == {name: "cartman", email: "cartman#sp.com"} # => False
The == operator check if every field of the hash have the same values. So .uniq will work how you want it to work!
If there is more than only the email and name field you should use the uniq method with a block:
foo.uniq { |x| [x[:name], x[:email]] }
It will keep only the uniq combination of the name and email.
Hope it helped, happy ruby coding!

Array#uniq takes a block:
foo = [{id: 1, name: 'Eric Cartman', email: 'eric#southpark.com'},
{id: 2, name: 'Eric Cartman', email: 'cartmanfamily#gmail.com'},
{id: 3, name: "Cartman's mom", email: 'cartmanfamily#gmail.com'},
{id: 4, name: 'Eric Cartman', email: 'eric#southpark.com'}]
bar = foo.uniq {|h| [h[:name], h[:email]] }
bar == [{id: 1, name: 'Eric Cartman', email: 'eric#southpark.com'},
{id: 2, name: 'Eric Cartman', email: 'cartmanfamily#gmail.com'},
{id: 3, name: "Cartman's mom", email: 'cartmanfamily#gmail.com'}] #=> true
Per the documentation, "If a block is given, it will use the return value of the block for comparison."

Related

How do I remove duplicate items from observable array based on multiple properties?

If I have an array of items like
[
{id: 1, name: 'Sam', gender: 'boy'},
{id: 2, name: 'Mary', gender: 'girl'},
{id: 3, name: 'Sam', gender: 'boy'}
]
Matching on just name and gender, how do I reduce it to the following result?
[
{id: 1, name: 'Sam', type: 'boy'},
{id: 2, name: 'Mary', type: 'girl'}
]
Let try
items$.pipe(map(this.uniqueArray))
uniqueArray(array: any[]): any[] {
return array.filter(
(item, index, self) =>
index === self.findIndex((x) => x.name === item.name)
);
}
https://stackblitz.com/edit/angular-isqjpa?file=src/app/hello.component.ts

Why do aggregating a filtered dataset lose the filters of it?

I have this collection:
// collection
[
{_id: 1, name: 'Luigi', childs: [{name: 'one'}, {name: 'two'}], dad_id: 9]},
{_id: 1, name: 'Mario', childs: [{name: 'four'}, {name: 'five'}], dad_id: 8]},
{_id: 1, name: 'Alessandro', childs: [{name: 'seven'}, {name: 'six'}], dad_id: 9]},
]
and apply this filter to it
result = collection.find({ dad_id: 9 })
Then I want to aggregate the results and get all the childs singularly, I start with unwinding them
(then I 'll make a projection, etc..) but I already encounter a behavior that I do not understand:
the result contains also the documents with dad_id is 8, even if they were already excluded by my query.
result.aggregate([
{ "$unwind"=> "$childs" },
]).each do |e| ... end
// => [
{_id: 1, name: 'Luigi', childs: {name: 'one'}, dad_id: 9]},
{_id: 1, name: 'Luigi', childs: {name: 'two'}, dad_id: 9]},
{_id: 1, name: 'Luigi', childs: {name: 'five'}, dad_id: 8]},
{_id: 1, name: 'Luigi', childs: {name: 'four'}, dad_id: 8]},
{_id: 1, name: 'Luigi', childs: {name: 'seven'}, dad_id: 9]},
{_id: 1, name: 'Luigi', childs: {name: 'six'}, dad_id: 9]},
]
What am I missing?
You can not chain input from one query to another query like that.
Either use search query ex. Model.find(id) or aggregation framework.
Aggregation framework provides you the functionality to create a pipeline (ex. match,unwind,lookup,project).
To utilize mongodb indexing always try to use "$match" first in the pipeline
match = { "$match" => { "dad_id" =>9} }
unwind = {"$uwind"=>"$childs"}
pipeline = [match,unwind]
collection.aggregate(pipeline).each do |obj|
end

Create nested hash RUBY

i have an array of hashes, eg
array = [
{ id: 1, name: 'root' parent: null},
{ id: 2, name: 'first' parent: 1},
{ id: 5, name: 'first step' parent: 2},
{ id: 6, name: 'second step' parent: 2},
{ id: 3, name: 'second' parent: 1},
{ id: 7, name: 'first step' parent: 3},
{ id: 4, name: 'third' parent: 1},
{ id: 2, name: 'first' parent: 1},
]
and i need to build something like that
hash = {
{
id: 1,
name: 'root',
parent: null,
childrens: [
{ id: 2,
name: 'first',
parent: 1,
childrens: [
{
id: 5,
name: 'first step',
parent: 2
},
{
id: 6,
name: 'second step',
parent: 2
},
]},
...
}
I am newbie at ruby and doesnot understand how to do this.
Probably i need to use recursive functions? Or not?
# Put all your nodes into a Hash keyed by id This assumes your objects are already Hashes
object_hash = nodes.index_by {|node| node[:id]}
object_hash[0] = {:root => true}
# loop through each node, assigning them to their parents
object_hash.each_value {|node|
next if node[:root]
children = object_hash[node[:parent_id]][:children] ||= []
children << node
}
#then your should have the structure you want and you can ignore 'object_hash' variable
tree = object_hash[0]
From the answer:
Algorithm for parsing a flat tree into a non-flat tree

Find intersection of two array of hashes depending upon hash contents

I get this two array of hashes after performing join
array 1
[#<State id: 1, name: "Alabama">, #<State id: 1, name: "Alabama">, #<State id: 1, name: "Alabama">, #<State id: 1, name: "Alabama">, #<State id: 2, name: "Alaska">, #<State id: 2, name: "Alaska">, #<State id: 4, name: "Arkansas">, #<State id: 4, name: "Arkansas">, #<State id: 4, name: "Arkansas">, #<State id: 6, name: "Colorado">, #<State id: 6, name: "Colorado">, #<State id: 6, name: "Colorado">, #<State id: 11, name: "Georgia">, #<State id: 14, name: "Illinois">, #<State id: 18, name: "Kentucky">, #<State id: 18, name: "Kentucky">, #<State id: 22, name: "Massachusetts">, #<State id: 48, name: "Washington">]
array 2
[#<City id: 1, name: "Abbeville", state_id: 1>, #<City id: 1, name: "Abbeville", state_id: 1>, #<City id: 1, name: "Abbeville", state_id: 1>, #<City id: 4543, name: "Abingdon", state_id: 14>, #<City id: 8282, name: "Accord", state_id: 22>, #<City id: 3808, name: "Acworth", state_id: 11>, #<City id: 6855, name: "Adairville", state_id: 18>, #<City id: 6855, name: "Adairville", state_id: 18>, #<City id: 18895, name: "Adams County", state_id: 6>, #<City id: 4, name: "Addison", state_id: 1>, #<City id: 4, name: "Addison", state_id: 1>, #<City id: 17510, name: "Addy", state_id: 48>, #<City id: 1054, name: "Adona", state_id: 4>, #<City id: 1054, name: "Adona", state_id: 4>, #<City id: 577, name: "Akiachak", state_id: 2>, #<City id: 1056, name: "Alicia", state_id: 4>, #<City id: 583, name: "Ambler", state_id: 2>, #<City id: 2783, name: "Aspen", state_id: 6>]
I want to make a third array from the above two based on the value of state_id in each array
in this case for example
[#, .... and so on
for your help the first two hashes array i got using join query
#states = State.joins("INNER JOIN property_of_interests ON property_of_interests.state_id = states.id").where(:property_of_interests => {:user_id => current_user.id})
#cities = City.joins("INNER JOIN property_of_interests ON property_of_interests.city_id = cities.id").where(:property_of_interests => {:user_id => current_user.id})
can I work on the query itself to get the desired output ?.
I tried something like
`#states.select("#states.name,#cities.name").joins("INNER JOIN #cities ON #cities.state_id = #states.id")`
but it doesnt work.
More Information
states
id, name
cities
id, name, state_id
property_of_interests
id, user_id, state_id, state_name
states has cities
cities belongs to states
states belongs to property_of_interests
cities belongs to property_of_interests
property_of_interests has cities
property_of_interests has states
Desired output like
State Name City Name
Alabama Abbeville
Alabama Abbeville
Alabama Abbeville
....
You would do something like:
City.all.each do |city|
puts "#{city.state.name} #{city.name}"
end
Alternately, as an array:
arr = City.all.map { |c| [c.state.name, c.name] }
Or as an array of hashes:
arr = City.all.map { |c| {state: c.state.name, city: c.name} }
Or to actually answer the question, since you want to start with the properties_of_interest table:
PropertyOfInterest.all.each do |prop|
prop.state.cities.each do |city|
puts prop.state.name, city.name
end
end

Split array. Ruby

Could you help me please with some problem?
I have array from database like this
str = Hiring::Tag.all
Hiring::Tag Load (0.1ms) SELECT `hiring_tags`.* FROM `hiring_tags`
=> [#<Hiring::Tag id: 1, name: "tag1", created_at: "2013-12-10 11:44:39", updated_at: "2013-12-10 11:44:39">,
#<Hiring::Tag id: 2, name: "tag2", created_at: nil, updated_at: nil>,
#<Hiring::Tag id: 3, name: "tag3", created_at: nil, updated_at: nil>,
#<Hiring::Tag id: 4, name: "wtf", created_at: "2013-12-11 07:53:04", updated_at: "2013-12-11 07:53:04">,
#<Hiring::Tag id: 5, name: "new_tag", created_at: "2013-12-11 10:35:48", updated_at: "2013-12-11 10:35:48">]
And I need to split this array like this:
data:[{id:1,name:'tag1'},{id:2,name:'tag2'},
{id:3,name:'tag3'},{id:4,name:'wtf'},{id:5,name:'new_tag'}]
Help me please!
if you use ActiveRecord 4.0
Hiring::Tag.pluck(:id, :name).map{ |id, name| {id: id, name: name} }
One possible solution:
Hiring::Tag.all.map {|h| {id: h.id, name: h.name} }
See the documentation for map.
You can try below code.
Hiring::Tag.all.inject({}) { |h, f| h[f.name.to_sym] = f.value; h }
OR
Hiring::Tag.all.map { |f| [f.name.to_sym, f.value] }]

Resources