I need to order an array of objects, composed by a name and a dependencies list (made out of names).
An example of this array could be:
[
{ name: 'a', requires: ['b', 'c'] },
{ name: 'b', requires: ['c'] },
{ name: 'c', requires: [] },
]
I'd like this array to be sorted so that the items which require a specific set of dependencies will be positioned after its required dependencies.
The array could actually contain more items, I'm okay if the sorting function throws an error in case of circular dependencies.
Example output:
[
{ name: 'c', requires: [] }, // first, no dependencies, and required by both the others
{ name: 'b', requires: ['c'] }, // second, because it needs `c` first
{ name: 'a', requires: ['b', 'c'] }, // last, because requires both the others
]
What's the most concise way to do it?
Summary: in this tutorial, you will learn how to sort an array of objects by the values of the object’s properties. To sort an array of objects, you use the sort () method and provide a comparison function that determines the order of objects. Suppose that you have an array of employee objects as follows:
The first item in pair is some object (item) and the second one is a collection of the same type objects that the first one depends on. I want to get a List<Item> in order of dependency, so there are not items that depend on the first element and so on (no cycled dependency!).
In the main () method, we’ve created an array list of custom objects list, initialized with 5 objects. For sorting the list with the given property, we use the list ‘s sort () method. The sort () method takes the list to be sorted (final sorted list is also the same) and a comparator.
To sort an array of objects, you use the sort () method and provide a comparison function that determines the order of objects. Suppose that you have an array of employee objects as follows: The following statement snippet sorts the employees array by ages in ascending order:
You can try following (changed test case to support more possible combinations)
var arr = [
{ name: 'd', requires: ['a', 'c'] },
{ name: 'a', requires: ['b', 'c'] },
{ name: 'b', requires: ['c'] },
{ name: 'e', requires: ['d'] },
{ name: 'c', requires: [] },
];
var map = {}; // Creates key value pair of name and object
var result = []; // the result array
var visited = {}; // takes a note of the traversed dependency
arr.forEach(function(obj){ // build the map
map[obj.name] = obj;
});
arr.forEach(function(obj){ // Traverse array
if(!visited[obj.name]) { // check for visited object
sort_util(obj);
}
});
// On visiting object, check for its dependencies and visit them recursively
function sort_util(obj){
visited[obj.name] = true;
obj.requires.forEach(function(dep){
if(!visited[dep]) {
sort_util(map[dep]);
}
});
result.push(obj);
}
console.log(result);
Update: thanks to Nina Scholz, I updated the code so that sort
should work
This might do the job.
The idea behind is, to user the sort
and check if element a
is in the requires of element b
. If so, we can assume, that a
should be before b
.
But I´m not 100% sure, I just checked against your example and the example of @nikhilagw. I might have forgotten something. Please let me know if it worked!
For every element, I additionally inherit all dependencies.
const list = [
{ name: 'b', requires: ['c'] },
{ name: 'e', requires: ['d'] },
{ name: 'd', requires: ['a', 'c'] },
{ name: 'c', requires: [] },
{ name: 'a', requires: ['b', 'c'] },
];
// indexed by name
const mapped = list.reduce((mem, i) => {
mem[i.name] = i;
return mem;
}, {});
// inherit all dependencies for a given name
const inherited = i => {
return mapped[i].requires.reduce((mem, i) => {
return [ ...mem, i, ...inherited(i) ];
}, []);
}
// order ...
const ordered = list.sort((a, b) => {
return !!~inherited(b.name).indexOf(a.name) ? -1 : 1;
})
console.log(ordered);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With