TIMEX
TIMEX

Reputation: 271614

How do I preserve the order of this javascript array sort?

const modules = [
{ name: 'Wood', checked: false },
{ name: 'Metal', checked: false },
{ name: 'Earth', checked: true },
{ name: 'Water', checked: false },
{ name: 'Air', checked: true },
{ name: 'Fire', checked: false },
]

I am trying to sort the array so that the True values come first , then False values.

const orderedModules = modules.sort((a, b) => (a.checked ? -1 : 1))

However, I'd like to preserve the order of the True values. The code above sometimes puts Air first, then Earth (if ran twice). How can I preserve the order all the time?

Upvotes: 2

Views: 1855

Answers (4)

Tony Zhang
Tony Zhang

Reputation: 427

the reason is that sort actually changes the original array. Although modules is defined with const, the values inside can change, as long as you don't assign the variable to something else.

according to this answer, you can sort without mutating the original using spread syntax. this code should work:

const orderedModules = [...modules].sort((a, b) => (a.checked ? -1 : 1))

to make an array or object not able to be modified, you can use Object.freeze()

const modules = Object.freeze([
    { name: 'Wood', checked: false },
    { name: 'Metal', checked: false },
    { name: 'Earth', checked: true },
    { name: 'Water', checked: false },
    { name: 'Air', checked: true },
    { name: 'Fire', checked: false },
])

Edit: I just realized the order isn't correct, but it at least is the same every time. but that's because the sorting isn't exactly right. here's the correct code:

const orderedModules = [...modules].sort((a, b) => (a.checked != b.checked ? (a.checked ? -1 : 1 ) : 0))

Upvotes: 0

Zion Ay
Zion Ay

Reputation: 301

The callback used as the compare function can return 3 options: negative number, positive number or zero. The negative number indicates that the first parameter should be before the second parameter in the array order. The positive number indicates that the first parameter should be after the second parameter in the array order. And zero means that the order should be kept as is.

Sort array method on MDN

If you want to order just the true values first in the same order in the array and then the false values, probably adding more logic to return zero from the compare function if both are true will solve your issue.

Here is an example:

const modules = [
  { name: 'Wood', checked: false },
  { name: 'Metal', checked: false },
  { name: 'Earth', checked: true },
  { name: 'Water', checked: false },
  { name: 'Air', checked: true },
  { name: 'Fire', checked: false },
];
modules.sort((a,b) => a.checked && b.checked ? 0 : a.checked ? -1 : 1);
console.log(modules);

Upvotes: 2

Raj Thakar
Raj Thakar

Reputation: 198

Probably this might help you. not sure for optimize way but this function iterate over an array one time only.

I am using reduce function to separate out true and false values and then return them in the order you want.

const shortItems = (array) => {
    const orderedModulesObject = array.reduce((orderedModulesObject, currentModule) => {
            if(currentModule.checked){
                orderedModulesObject.trueValues = orderedModulesObject.trueValues.concat(currentModule);
            } else {
                orderedModulesObject.falseValues = orderedModulesObject.falseValues.concat(currentModule);
            }
            return orderedModulesObject;
        
    }, { trueValues: [], falseValues: []});
    return orderedModulesObject.trueValues.concat(orderedModulesObject.falseValues);
}

const modules = [
{ name: 'Wood', checked: false },
{ name: 'Metal', checked: false },
{ name: 'Earth', checked: true },
{ name: 'Water', checked: false },
{ name: 'Air', checked: true },
{ name: 'Fire', checked: false },
]

console.log(shortItems(modules));

Upvotes: 0

גלעד ברקן
גלעד ברקן

Reputation: 23955

If you don't mind creating a new array, just iterate over the array twice. The first time, push to the new array the objects with the true values as the iteration encounters them. The second time, push the objects with the false values. (JavaScript passes objects by reference so the new array won't cause them to get duplicated.)

Upvotes: 1

Related Questions