Smally
Smally

Reputation: 1684

Reorder array based on values

I have an array with classes (the class is called Note), and in those classes are basic values. Two important values are the Note.Pinned (boolean whether it's pinned or not) and Note.Modified (a timestamp when it was last edited).

I would like to sort this array of classes by the Modified timestamp, then reorder it that the Pinned notes are on top of this list.

I already tried sorting the notes.

const SortedNotes = Notes.sort((a, b) => a.Modified > b.Modified);

Notes being the array with classes.

But, then, is there a better way to rearrange this array? Or is this the only method I can use?

SortedNotes.filter(n => n.Pinned).concat(SortedNotes.filter(n => !n.Pinned));

The above would work, and I know I can use Array.prototype.partition, so is there any other way of doing this?

Thanks

Upvotes: 0

Views: 1514

Answers (5)

Smally
Smally

Reputation: 1684

I edited @Ja͢ck's answer to be a little more compact.

const SortedNotes = Notes.sort((a, b) => {
    if (a.Pinned == b.Pinned) return a.Modified > b.Modified ? -1 : 1;
    else return a.Pinned ? -1 : 1;
});

Upvotes: 0

Ja͢ck
Ja͢ck

Reputation: 173572

You can sort by multiple conditions:

const SortedNotes = Notes.sort((a, b) => {
  if (a.Pinned == b.Pinned) {
    if (a.Modified > b.Modified) return -1;
    if (a.Modified < b.Modified) return 1;
  } else {
    return a.Pinned ? -1 : 1;
  }
});

The missing branch of a.Pinned == b.Pinned && a.Modified == b.Modified would return undefined, which in turn would be interpreted as equal.

Btw, the array Notes itself would've been modified in place, so both SortedNotes and Notes would exhibit the same ordering; of course, assigning to a const variable can't hurt.

Upvotes: 1

James Coyle
James Coyle

Reputation: 10398

You can just add the pinned sorting requirement to the sort:

const arr = [{
    pinned: false,
    modified: 7
  },
  {
    pinned: false,
    modified: 6
  },
  {
    pinned: true,
    modified: 2
  },
  {
    pinned: false,
    modified: 4
  },
  {
    pinned: true,
    modified: 1
  },
  {
    pinned: true,
    modified: 8
  },
  {
    pinned: false,
    modified: 3
  },
]

arr.sort((a, b) => {
  if (a.pinned != b.pinned)
    return a.pinned ? -1 : 1;
  return b.modified - a.modified;
})

console.log(arr)

As long as the execution of the sort function returns the same result for the same two given parameters the sort will work fine. Knowing this, you can handle the two states where the pinned state is different and then sort by modified only if the pinned state is the same.

Upvotes: 2

Nghĩa Nguyễn
Nghĩa Nguyễn

Reputation: 1

Shorter, you can try

const SortedNotes = Notes.sort((a, b) => {
    if (a.Pinned > b.Pinned)
       return 1;
    if (a.Pinned == b.Pinned) 
       return a.Modified > b.Modified;
    return -1;
})

Upvotes: 0

Chris
Chris

Reputation: 59511

Not the best solution perhaps, but this should help you in the right direction. This sorts the array so that notes are in decending date order, with the pinned ones at the top.

Unlike other (better) answers, this has a O(2n) sorting complexity, so bear that in mind.

const notes = [
  {
    text: "foo",
    modified: 1583337610387,
    pinned: false
  },
  {
    text: "bar",
    modified: 1583337610388,
    pinned: true
  },
  {
    text: "baz",
    modified: 1583337610389,
    pinned: false
  },
  {
    text: "qux",
    modified: 1583337610390,
    pinned: true
  }
];

const sortedNotes = [...notes];
sortedNotes.sort((a, b) => a.modified > b.modified ? -1 : 1);
sortedNotes.sort((a, b) => (a.pinned === b.pinned) ? 0 : a.pinned ? -1 : 1);
console.log(sortedNotes);

Upvotes: 2

Related Questions