Create nested hash RUBY - 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

Related

Searching through an elastic search document not knowing the path

I want to search through a document and get data for Steven and all his children (so in this example James).
{
name: "John",
a: 1,
b: 2,
children:
[
{
name: Mark,
a: 3,
b: 5,
children:
[
{
name: "Steven",
a: 2,
b: 5,
children: [{ name: "James", a: 1, b: 5 }],
},
],
},
{ name: "David", a: 3, b: 5 }
],
}
Is there a way to do it not knowing the path for Steven - so it should be children.children.name - but what if I don't know on which level Steven occurs? Is it even possible in Elasticsearch? The data type of my field is nested.

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

How to add an array of new data to a D3 hierarchy?

I'm working with a tree of hierarchical data, on the server side. I need to compute some parameters for each branch with scheduled functions after updating the tree hierarchy.
My problem is: how do I take a d3.hierarchy on one side, and an array of new documents on the other, and get a new hierarchy?
here is some data:
let collection = [
{ id: 0, rank: 0 },
{ id: 1, parent: 0},
{ id: 2, parent: 0},
{ id: 3, parent: 1},
{ id: 4, parent: 1},
{ id: 5, parent: 1},
{ id: 6, parent: 1},
{ id: 7, parent: 2},
{ id: 8, parent: 2},
{ id: 9, parent: 2},
{ id: 10, parent: 3},
{ id: 11, parent: 3},
{ id: 12, parent: 3},
{ id: 13, parent: 3},
{ id: 14, parent: 4},
{ id: 15, parent: 5},
{ id: 16, parent: 5},
{ id: 17, parent: 6},
{ id: 18, parent: 6},
{ id: 19, parent: 6},
{ id: 20, parent: 6},
{ id: 21, parent: 7},
{ id: 22, parent: 7},
{ id: 23, parent: 7},
{ id: 24, parent: 8},
{ id: 25, parent: 8},
{ id: 26, parent: 9},
{ id: 27, parent: 9},
]
let root = d3
.stratify()
.id(d => d.id)
.parentId(d => d.parent)(collection)
console.log(root)
vvvvvvvvvvvv prints vvvvvvvvv
Node {
data: { id: 0, rank: 0 },
height: 3,
depth: 0,
parent: null,
id: '0',
children:
[ Node {
data: [Object],
height: 2,
depth: 1,
parent: [Circular],
id: '1',
children: [Array] } ] }
const newElements = [
{ id: 28, parent: 16},
{ id: 29, parent: 6},
{ id: 30, parent: 12},
{ id: 31, parent: 19},
{ id: 32, parent: 28},
{ id: 33, parent: 7},
{ id: 34, parent: 33},
]
So root is the ('object'??) I'm working with on the server, and newElements the things I would like to add to root.

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

Enumeration through hash and keeping separate key value pairs of a key that are the same

I have this array of objects:
a = [#<Person id: 9, name: "Bob", bin_id: "114628">,
#<Person id: 10, name: "Sally", bin_id: "114626">,
#<Person id: 11, name: "Jessie", bin_id: "114627">,
#<Person id: 12, name: "Rapheal", bin_id: "114620">,
#<Company _id: 55295, name: "X", bin_id: "114619">,
#<Company _id: 55295, name: "Y", bin_id: "114629">,
#<Company _id: 55295, name: "Z", bin_id: "16074802">,
#<Company _id: 55295, name: "W", bin_id: "16074815">]
When I do
a.group_by { |objects| object.calculate_age }
I get this:
{
33 =>
[#<Person id: 9, name: "Bob", bin_id: "114628">,
#<Person id: 10, name: "Sally", bin_id: "114626">,
#<Person id: 11, name: "Jessie", bin_id: "114627">],
53 => [#<Company _id: 55295, name: "X", bin_id: "114619">],
45 => [#<Company _id: 55295, name: "Y", bin_id: "114629">,],
56 => [#<Company _id: 55295, name: "Z", bin_id: "16074802">],
60 => [#<Company _id: 55295, name: "W", bin_id: "16074815">]
}
But how I do get something that looks like this:
{
33 => [#<Person id: 9, name: "Bob", bin_id: "114628">],
33 => [#<Person id: 10, name: "Sally", bin_id: "114626">],
33 => [#<Person id: 11, name: "Jessie", bin_id: "114627">],
53 => [#<Company _id: 55295, name: "X", bin_id: "114619">],
45 => [#<Company _id: 55295, name: "Y", bin_id: "114629">,],
56 => [#<Company _id: 55295, name: "Z", bin_id: "16074802">],
60 => [#<Company _id: 55295, name: "W", bin_id: "16074815">]
}
Where each key is explicitely set to each value? Maybe group_by isn't the right method here. I want to return a hash like you see above.
For the purposes of your question, you could write your array:
arr = [obj0, obj1,...,obj7]
since the values of the each object's instance variables are irrelevant. You can't convert that to a hash with duplicate keys (age), but you could convert it to an array of hashes, each with a single key, age, if that would be helpful:
arr.map { |obj| { obj.calculate_age=>obj } }
To see how that would work, suppose we have:
class Friends
attr_reader :calculate_age
def initialize name, age
#name, #calculate_age = name, age
end
end
a = [["Amy", 21], ["Billy-Bob", 53], ["Wilber", 21], ["Trixi", 34], ["Bo", 53]]
arr = a.map { |name,age| Friends.new(name,age) }
#=> [#<Friends:0x007fc1f28b5518 #name="Amy", #calculate_age=21>,
# #<Friends:0x007fc1f28b54a0 #name="Billy-Bob", #calculate_age=53>,
# #<Friends:0x007fc1f28b5450 #name="Wilber", #calculate_age=21>,
# #<Friends:0x007fc1f28b5400 #name="Trixi", #calculate_age=34>,
# #<Friends:0x007fc1f28b5388 #name="Bo", #calculate_age=53>]
We can now convert this to an array of hashes:
a = arr.map { |obj| { obj.calculate_age=>obj } }
#=> [{21=>#<Friends:0x007fc1f28b5518 #name="Amy",...},
# {53=>#<Friends:0x007fc1f28b54a0 #name="Billy-Bob",...},
# {21=>#<Friends:0x007fc1f28b5450 #name="Wilber"...},
# {34=>#<Friends:0x007fc1f28b5400 #name="Trixi"...},
# {53=>#<Friends:0x007fc1f28b5388 #name="Bo",...}]
If you want those arrays sorted by age:
a.sort_by { |h| h.keys.first }
#=> [{21=>#<Friends:0x007fc1f28b5518 #name="Amy",...},
# {21=>#<Friends:0x007fc1f28b5450 #name="Wilber"...},
# {34=>#<Friends:0x007fc1f28b5400 #name="Trixi"...},
# {53=>#<Friends:0x007fc1f28b54a0 #name="Billy-Bob",...},
# {53=>#<Friends:0x007fc1f28b5388 #name="Bo",...}]

Resources