Array.sort() only for elements that have a specific key

I have an array like:

let arr = [
     { 
      label: "abc",
      value: 2,
      checked: true
     },
     { 
      label: "bcd",
      value: 1,
      checked: true
     },
     { 
      label: "cde",
      value: 4,
      checked: false
     },{ 
      label: "def",
      value: 6,
      checked: true
     },
     { 
      label: "efg",
      value: 3,
      checked: false
     },
     { 
      label: "fgh",
      value: 5,
      checked: true
     }
   ]

I'm trying to sort this in two different ways ( alphabetically, by value ). The current implementation of the sort works properly, but I'm running into some issues when I'm sorting by value... How can I obtain an array of these values from 'arr' sorted descending by value only when the checked flag is true? I mean... I want to sort by value only the elements that are checked and for the rest of the elements to preserve them as they are at the initial index...

    //expected result
    let arr = [
     {                   //sorted index 0
      label: "bcd",
      value: 1,
      checked: true
     },
     {                   //sorted index 1 
      label: "abc",
      value: 2,
      checked: true
     },
     {                   //checked: false - perserve index (2) from the initial array 
      label: "cde",
      value: 4,
      checked: false
     },
     {                   //sorted index 3 
      label: "fgh",
      value: 5,
      checked: true
     },
     {                   //checked: false - perserve index (4) from the initial array 
      label: "efg",
      value: 3,
      checked: false
     },
     {                   //sorted index 5 
      label: "def",
      value: 6,
      checked: true
     }
   ]

Is there a simple way to use lodash? Or is it needed to do it manually, and how?

Upvotes: 0

Views: 84

Answers (4)

Sven.hig
Sven.hig

Reputation: 4519

I know I am late but here is a different appreach using bubbling

for(let i=0;i<arr1.length-1;i++){
    for(let j=0;j<arr1.length-i-1;j++){
      if(arr1[j].checked==true){
        if(arr1[j].value>arr1[j+1].value){ 
            v=arr1[j]
          arr1[j]=arr1[j+1]  
          arr1[j+1]=v
        }
      }
    }
  }

Upvotes: 0

Cat
Cat

Reputation: 4226

This solution works by copying the checked items into a separate array, sorting them, then reinserting them into (a copy of) the original array.

const

  // Gets the original array
  arr = getArr()

  // Defines a function to use for sorting
  compare = (a, b) => a.value - b.value,

  // Makes an array of just the objects where `.checked` is truthy, and sorts it
  partSorted = arr
    .filter(obj => obj.checked)
    .sort(compare);

// Defines a variable to track the index within the `partSorted` array
let i = 0;

// Copies `arr`, but substitutes the next item from `partSorted` if appropriate
const sorted = arr.map(obj => 
  obj.checked ? partSorted[i++] : obj
);

// Shows the result
console.log(sorted);


// Defines the original array
function getArr(){
  return [
    { label: "abc", value: 2, checked: true  },
    { label: "bcd", value: 1, checked: true  },
    { label: "cde", value: 4, checked: false },
    { label: "def", value: 6, checked: true  },
    { label: "efg", value: 3, checked: false },
    { label: "fgh", value: 5, checked: true  }
  ];
}

Upvotes: 2

Nina Scholz
Nina Scholz

Reputation: 386550

You could store the indices to put the sorted values back and take the objects for sorting. Sort and apply back.

var array = [{ label: "abc", value: 2, checked: true }, { label: "bcd", value: 1, checked: true }, { label: "cde", value: 4, checked: false }, { label: "def", value: 6, checked: true }, { label: "efg", value: 3, checked: false }, { label: "fgh", value: 5, checked: true }],
    indices = [];

array
    .filter(({ checked }, i) => checked && indices.push(i))
    .sort(({ value: a }, { value: b }) => a - b)
    .forEach((v, i) => array[indices[i]] = v);

console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 2

ardean
ardean

Reputation: 162

You can use native JavaScript sort. 1 and -1 changes the sort position, 0 will keep the order. If it is reversed then change a with b.

arr.sort((a, b) => a.checked ? b.value - a.value : 0);

Upvotes: 0

Related Questions