loraine
loraine

Reputation: 39

Sort only one value in array

How do I sort banana after apple always?

    arr = [
          { 'id' : 1, 'fruit' : 'apple' },
          { 'id' : 2, 'fruit' : 'banana' },
          { 'id' : 3, 'fruit' : 'custard' },
          { 'id' : 4, 'fruit' : 'banana' },
          { 'id' : 5, 'fruit' : 'apple' },
          { 'id' : 6, 'fruit' : 'custard' } 
        ];

expected:

      arr = [
          { 'id' : 1, 'fruit' : 'apple' },
          { 'id' : 3, 'fruit' : 'custard' },
          { 'id' : 5, 'fruit' : 'apple' },
          { 'id' : 2, 'fruit' : 'banana' },
          { 'id' : 4, 'fruit' : 'banana' },
          { 'id' : 6, 'fruit' : 'custard' } 
        ];

So banana should always appear after apple, or apple should be sorted before banana.

this is what i've tried:

arr.sort(function(a, b) {
      return (a.fruit === 'banana') - (b.fruit === 'banana') 
})

but in this case, banana always gets sorted at the end of the array, which is not what i'm going for. all the 'banana' items should be automatically sorted after the last 'apple' item

Upvotes: 0

Views: 523

Answers (2)

trincot
trincot

Reputation: 350137

You can simply sort by item2 (alphabetically).

arr.sort((a, b) => a.item2.localeCompare(b.item2));

This will put all records in alphabetical order based on item2.

If however you want to perform the minimum number of swaps, then I suggest you don't use sort, but loop the array by bringing two indices towards each other starting at both ends:

let arr = [
      { 'item1' : 1, 'item2' : 'apple' },
      { 'item1' : 2, 'item2' : 'banana' },
      { 'item1' : 3, 'item2' : 'custard' },
      { 'item1' : 4, 'item2' : 'banana' },
      { 'item1' : 5, 'item2' : 'apple' },
      { 'item1' : 6, 'item2' : 'custard' } 
];

let i = 0;
let j = arr.length-1;
while (true) {
    while (i < j && arr[i].item2 !== "banana") {
        i++;
    }
    while (i < j && arr[j].item2 !== "apple") {
        j--;
    }
    if (i >= j) {
        break;
    }
    [arr[i], arr[j]] = [arr[j], arr[i]]; // swap
    i++;
    j--;
}

console.log(arr);

Upvotes: 1

Carsten Massmann
Carsten Massmann

Reputation: 28196

This will in a first step separate the array into two: res[true] containing all the "banana"-elements and res[false] all the others. In a second step the array res[true] is .splice()-ed into the res[false] array after the last index of "apple".

const arr = [
      { 'item1' : 1, 'item2' : 'apple' },
      { 'item1' : 2, 'item2' : 'banana' },
      { 'item1' : 3, 'item2' : 'custard' },
      { 'item1' : 4, 'item2' : 'banana' },
      { 'item1' : 5, 'item2' : 'apple' },
      { 'item1' : 6, 'item2' : 'custard' } 
    ];

let res=arr.reduce(
  (a,c)=>(a[c.item2==="banana"].push(c),a),
  {true:[],false:[]} );
  
let pos=res[false].map(e=>e.item2).lastIndexOf("apple")+1;
// in case "apple" was not found: simply copy arr:
res=pos?(res[false].splice(pos,0,...res[true]),res[false]):arr.slice(0);
console.log(res);

res contains the final result.

Upvotes: 0

Related Questions