Javascript - Sort the elements of the array without changing positions of certain elements using Array.sort()

Viewed 273

I have multiple numeric arrays where elements with a value of -1 are located in certain positions. Arrays must be sorted in ascending order without changing the positions of elements with a value of -1. I can't create a right comparison function in sort(function (a,b){}). Тhe results of sorting the following arrays should look like this:

[-1,150,190,170,-1,-1,160,180] result [-1,150,160,170,-1,-1,180,190].
[-1,2,-1,8,-1,4]) result [-1,2,-1,4,-1,8].
[-1,-1,-1,-1,-1]) result [-1,-1,-1,-1,-1].
[4,2,9,11,2,16]) result [2,2,4,9,11,16].

This code

return x.sort(function (a,b) {
    if (a==-1) return 0;
    // if (b==-1) return 0;
    if (a < b) return -1;
    if (a > b) return 1;
    return 0;
});

doesn't work correctly in first example, result look like this [-1,150,160,170,190,-1,-1,180]. And doesn't work at all on second example.

3 Answers

You can do the following,

function sortArr(arr) {
  const sortedArr = arr.filter(item => item !== -1).sort((a,b) => a-b);
  let cnt = 0;
  return arr.map(item => {
    if (item === -1) return -1;
    else return sortedArr[cnt++];
  });
}
console.log(sortArr([-1,150,190,170,-1,-1,160,180]));
console.log(sortArr([-1,2,-1,8,-1,4]));
console.log(sortArr([-1,-1,-1,-1,-1]));
console.log(sortArr([4,2,9,11,2,16]));

What I would do is filter out the negative numbers into another array sort, and then pop back into the original..

eg.

function sorter(arr) {
  const nums = arr.filter(
    b => b >= 0).sort((a,b) => b - a);
  for (let l = 0; l < arr.length; l += 1) { 
    if (arr[l] >= 0) arr[l] = nums.pop();
  }
  return arr;
}

console.log(sorter(
  [-1,150,190,170,-1,-1,160,180]).
  join(','));
console.log(sorter(
  [-1,2,-1,8,-1,4]).
  join(','));
console.log(sorter(
  [-1,-1,-1,-1,-1]).
  join(',')
  );
console.log(sorter(
  [4,2,9,11,2,16]).
  join(',')
  );

This is an approach by using sort directly, but shaping the access with a Proxy for length and the indices.

const
    sort = (array, sortFn, filterFn = _ => true) => {
        const indices = [...array.keys()].filter(i => filterFn(array[i]));
        new Proxy(array, {
            get (target, prop) {
                if (isFinite(prop)) return target[indices[prop]];
                if (prop === 'length') return indices.length;
                return target[prop];
            },
            set (target, prop, receiver) {
                target[indices[prop]] = receiver;
                return true;
            }
        })
        .sort(sortFn);

        return array;
    };    
    
console.log(...sort(
    [-1, 150, 190, 170, -1, -1, 160, 180],
    (a, b) => a - b,
    v => v !== -1
));

Related