Reputation: 302
I know there are a lot of sort
related issues but I can not find my solution.
I have data like this:
const list = [
{
name: 'one',
next: 'two'
},
{
name: 'three',
next: 'four'
},
{
name: 'four',
next: 'five'
},
{
name: 'two',
next: 'three'
},
]
And I want to classify them according to the next
property.
I don't want to sort by alphabetical order. But by the next property.
If a.next === b.name
then he come first.
I tried this :
list.sort((a, b) => {
if (a.next === b.name) {
return -1
}
})
How can I achieve this ?
Result I want :
list = [
{
name: 'one',
next: 'two'
},
{
name: 'two',
next: 'three'
},
{
name: 'three',
next: 'four'
},
{
name: 'four',
next: 'five'
}
]
Upvotes: 2
Views: 94
Reputation: 51936
Assuming that there are no cycles or forks in the chain, you can sort this list out-of-place in O(n) using the following function:
const list = [
{
name: 'one',
next: 'two'
},
{
name: 'three',
next: 'four'
},
{
name: 'four',
next: 'five'
},
{
name: 'two',
next: 'three'
}
]
function sortLinkedListBy(list, from, to) {
// collect list of items into dictionary<name, <next, item>>
// collect next keys into Set<string>
const { map, set } = list.reduce(({ map, set }, item) => {
const { [from]: name, [to]: next } = item
map.set(name, { next, item })
set.add(next)
return { map, set}
}, { map: new Map(), set: new Set() })
// locate single name that does not exist in set of next keys
const [key] = Array.from(map.keys()).filter(key => !set.has(key))
// reduce list (to iterate same amount of times as number of items)
// accumulator is a tuplet containing sorted list and next key in chain
const { list: sorted } = list.reduce(({ list, key: name }) => {
const { next, item } = map.get(name)
list.push(item)
return { list, key: next }
}, { list: [], key })
return sorted
}
console.log(sortLinkedListBy(list, 'name', 'next'))
Upvotes: 1
Reputation: 26844
Assuming the array is sortable based on the required logic. You can:
You can organize the array into an object using reduce
. Get the first element by checking if the name does not exist as a next. Use the classic for
to loop in the length of the array.
const list = [{"name":"one","next":"two"},{"name":"three","next":"four"},{"name":"four","next":"five"},{"name":"two","next":"three"}];
const order = list.reduce((c, v, i) => Object.assign(c, {[v.name]: v}), {}); //Make an order object. This will make it easier to get the values. Use the name as the key
let key = Object.keys(order).find(o => !list.some(x => x.next === o)); //Find the first element. Element that is not found on next
let result = [];
for (i = 0; i < list.length; i++) { //Loop thru the array. Get the value from order object.
result.push(order[key]); //Push the array from the object order
key = order[key].next; //overide the key with the next
}
console.log(result);
Upvotes: 4