Reputation: 2517
If I have an array with a bunch of posts sorted any old how:
[
{
id: 1,
name: "first parent post"
},
{
id: 2,
name: "second child of first parent post"
},
{
id: 3,
name: "second parent post"
},
{
id: 4,
name: "first child of first parent post"
},
{
id: 5,
name: "first child of second parent post"
}
]
However, another array decides the structure of the first array based on the ids of the first array:
[
{
id: 1,
parent: 0
},
{
id: 4,
parent: 1
},
{
id: 2,
parent: 1
},
{
id: 3,
parent: 0
},
{
id: 5,
parent: 3
}
]
What would be the most efficient way to sort these so that the first array is sorted by the second array?
I would expect the resulting array to look something like this:
[
{
id: 1,
name: "first parent post",
indent: 0
},
{
id: 4,
name: "first child of first parent post",
indent: 1
},
{
id: 2,
name: "second child of first parent post",
indent: 1
},
{
id: 3,
name: "second parent post",
indent: 0
},
{
id: 5,
name: "first child of second parent post",
indent: 1
}
]
Upvotes: 0
Views: 73
Reputation: 8584
For the ordering, convert the first array into a Map
, then pull the information from that into the first array.
function combineArrays(arr1, arr2) {
let names = new Map(arr1.map(({id, name}) => [id, name]));
return arr2.map(({id, parent}) => ({id: id, name: names.get(id), parent: parent}));
}
This will give you name
, id
, and parent
in the order you want. Calculating indent
is left as an exercise to the reader (or should probably be a different question).
Upvotes: -1
Reputation: 386550
You need to generate a tree with the dependencies first and then render the indent for all items of the orginal array.
This proposal works for unsorted data/relations as well.
function getDataWithIndent(data, relation) {
var hash = Object.create(null),
tree = function (data, root) {
var r = [], o = {};
data.forEach(function (a) {
a.children = o[a.id] && o[a.id].children;
o[a.id] = a;
if (a.parent === root) {
r.push(a);
} else {
o[a.parent] = o[a.parent] || {};
o[a.parent].children = o[a.parent].children || [];
o[a.parent].children.push(a);
}
});
return r;
}(relation, 0),
result = [];
data.forEach(function (a) {
hash[a.id] = a;
});
tree.forEach(function iter(indent) {
return function (a) {
hash[a.id].indent = indent;
result.push(hash[a.id]);
Array.isArray(a.children) && a.children.forEach(iter(indent + 1));
};
}(0));
return result;
}
var data = [{ id: 1, name: "first parent post" }, { id: 2, name: "second child of first parent post" }, { id: 3, name: "second parent post" }, { id: 4, name: "first child of first parent post" }, { id: 5, name: "first child of second parent post" }],
relation = [{ id: 1, parent: 0 }, { id: 4, parent: 1 }, { id: 2, parent: 1 }, { id: 3, parent: 0 }, { id: 5, parent: 3 }],
result = getDataWithIndent(data, relation);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 1
Reputation: 18734
You can order your data array by index and then order it by the order array;
to get the indentation you'll have to track the parent's indentation upstream and add one:
var data = [
{
id: 1,
name: "first parent post"
},
{
id: 2,
name: "second child of first parent post"
},
{
id: 3,
name: "second parent post"
},
{
id: 4,
name: "first child of first parent post"
},
{
id: 5,
name: "first child of second parent post"
}
]
var ord = [
{
id: 1,
parent: 0
},
{
id: 4,
parent: 1
},
{
id: 2,
parent: 1
},
{
id: 3,
parent: 0
},
{
id: 5,
parent: 3
}
]
// first you arrange the data element by index
dataByIndex = data.reduce((ac, x) => {
ac[x.id] = x;
return ac
},[])
// then you order them by the ord array
var res = ord.reduce((ac, x, i) => {
var item = dataByIndex[x.id]
item.indent = x.parent === 0 ? 0 : getParentIndentPlusOne(ac, x.parent)
return [...ac, item]
}, [] )
function getParentIndentPlusOne(ac, id){
var i = ac.length
while (--i > -1){
if (id === ac[i].id) return ac[i].indent + 1
}
}
console.log(res)
Upvotes: 1