[javascript] 내림차순으로 시작하지만 ‘0’은 시작에 정렬

JavaScript에서 이미 한동안 알아 내려고 노력하고 있습니다.

이 배열을 고려하십시오.

let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5];

이 결과를 출력해야합니다.

arr = [0, 0, 0, 0, 0, 5, 4, 3, 2, 1]

이 논리 라인을 따라 0을 앞에 놓고 인덱스 값을 조정합니다.

arr.sort((x, y) => {
    if (x !== 0) {
        return 1;
    }

    if (x === 0) {
        return -1;
    }

    return y - x;
});

그러나 나는이 결과에 갇혀있다.

arr = [0, 0, 0, 0, 0, 1, 2, 3, 4, 5]

누구든지 이것을 해결하는 방법에 대한 팁이 있습니까?



답변

ba(내림차순 정렬) 의 델타를 기준으로 정렬하고 Number.MAX_VALUE0과 같은 잘못된 값을 취할 수 있습니다 .

이:

Number.MAX_VALUE - Number.MAX_VALUE

0과 같습니다.

let array = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5];

array.sort((a, b) => (b || Number.MAX_VALUE) - (a || Number.MAX_VALUE));

console.log(...array);


답변

MDN 문서는 다음과 같이 말합니다.

a와 b가 비교되는 두 요소 인 경우 :

경우 compareFunction(a, b)반환 미만 0, 일종의 a인덱스보다 낮은 b(즉, 먼저 온다).

compareFunction(a, b)0을 반환 하면 a와 b는 서로 변경되지 않고 모든 다른 요소에 대해 정렬됩니다. 참고 : ECMAscript 표준은이 동작을 보증하지 않으므로 모든 브라우저 (예 : 2003 년 이전의 Mozilla 버전)가이를 존중하지는 않습니다.

compareFunction(a, b)
0보다 큰 값을 반환 하면 ba보다 낮은 인덱스를 기준으로 정렬 하십시오 (즉, b우선).

compareFunction(a, b)요소의 특정 쌍 주어 졌을 때 항상 같은 값을 반환해야 a하고 b두 개의 인수로합니다. 일치하지 않는 결과가 반환되면 정렬 순서가 정의되지 않은 것입니다.

따라서 비교 함수의 형식은 다음과 같습니다.

function compare(a, b) {
  if (a is less than b by some ordering criterion) {
    return -1;
  }
  if (a is greater than b by the ordering criterion) {
    return 1;
  }
  // a must be equal to b
  return 0;
}

let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5];

arr.sort((x, y) => {
    if (x > 0 && y > 0) {
        return y - x;
    }
    return x - y;
});

console.log(arr);


답변

효율성에 관심이 있다면 0을 먼저 필터링하는 것이 가장 빠를 것입니다 . sort특별한 경우를 처리하기 위해 비교 콜백에 추가 작업을 추가하는 것 외에도 시간을 낭비 하고 싶지는 않습니다 .

특히 많은 수의 0을 예상하는 경우 각 0을 여러 번 볼 수있는 더 큰 O (N log N) 정렬을 수행하는 것보다 필터링하여 데이터를 한 번 통과하는 것이 훨씬 좋습니다.

완료 후 올바른 수의 0을 효율적으로 추가 할 수 있습니다 .

결과 코드를 읽는 것만 큼 쉽습니다. 효율적이고 숫자 정렬을 쉽게하기 때문에 TypedArray를 사용했습니다 . 그러나 (a,b)=>a-bfor 의 표준 관용구를 사용하여이 기술을 일반 Array와 함께 사용할 수 있습니다 .sort.

let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5];

let nonzero_arr = Int32Array.from(arr.filter(n => n != 0));
let zcount = arr.length - nonzero_arr.length;
nonzero_arr.sort();      // numeric TypedArray sorts numerically, not alphabetically

// Reverse the sorted part before copying into the final array.
nonzero_arr.reverse();

 // efficient-ish TypedArray for main result
let revsorted = new Int32Array(arr.length);   // zero-filled full size
revsorted.set(nonzero_arr, zcount);           // copy after the right number of zeros

console.log(Array.from(revsorted));      // prints strangely for TypedArray, with invented "0", "1" keys

/*
   // regular Array result
let sorted = [...Array(zcount).fill(0), ...nonzero_arr]  // IDK if this is efficient
console.log(sorted);
*/

하는 TypedArray는 나도 몰라 .sort()하고 .reverse빠른 내림차순으로 정렬하는 사용자 정의 비교 함수를 사용하는 것보다. 또는 반복자를 사용하여 즉석에서 복사 및 반전 할 수 있다면.


또한 고려할 가치가 있습니다. 전체 길이 중 하나의 TypedArray 만 사용하십시오 .

사용하는 대신 .filter, 그 위에 루프 및 교환 이가는대로 배열의 전면에 0을. 이것은 데이터를 한 번 넘깁니다.

그런 다음을 사용 .subarray()하여 동일한 기본 ArrayBuffer의 0이 아닌 요소에 대한 새로운 TypedArray 뷰를 가져옵니다. 정렬하면 0이 아닌 요소 만 볼 수 있으며 시작이 0이고 꼬리가 정렬 된 전체 배열이됩니다.

Array 또는 TypedArray 메서드에서 파티션 함수를 보지 못했지만 JavaScript는 거의 알지 못합니다. 좋은 JIT를 사용하면 루프가 내장 메소드보다 훨씬 나빠서는 안됩니다. (특히 해당 메소드에 콜백이 포함 되어 있고 후드에서 축소하기 위해 .filter사용하지 않는 한 realloc실제로 필터링하기 전에 할당 할 메모리 양을 파악해야합니다).

TypedArray로 변환하기 .filter() 전에 regular-Array 사용했습니다 . 입력이 이미 TypedArray 인 경우이 문제가 없으며이 전략이 더욱 매력적입니다.


답변

다음과 같이 비교 함수의 조건을 수정하십시오.

let arr = [-1, 0, 1, 0, 2, -2, 0, 3, -3, 0, 4, -4, 0, 5, -5];
arr.sort((a, b) => {
   if(a && b) return b-a;
   if(!a && !b) return 0;
   return !a ? -1 : 1;
});

console.log(arr);


답변

코드 골프를하지 않는 경우 :

let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5, -1];
arr.sort(function(a, b) {
  if (a === 0 && b !== 0) {
    // a is zero b is nonzero, a goes first
    return -1;
  } else if (a !== 0 && b === 0) {
    // a is nonzero b is zero, b goes first
    return 1;
  } else {
    // both are zero or both are nonzero, sort descending
    return b - a;
  }
});
console.log(arr.toString());


답변

이미 존재하는 숫자 정렬을 쓰지 마십시오. 당신이하고 싶은 것은 제목에서 정확히 말한 것입니다. 시작시 0을 제외하고 내림차순으로 숫자를 정렬하십시오.

const zeroSort = arr => [...arr.filter(n => n == 0),
                         ...new Float64Array(arr.filter(n => n != 0)).sort().reverse()];

console.log(zeroSort([0, 1, 0, 2, 0, 3, 0, 4, 0, 500]));

필요하지 않은 코드는 작성하지 마십시오. 잘못 될 수도 있습니다.

배열이 처리 할 숫자 유형에 따라 TypedArray 를 선택하십시오 . Float64는 모든 일반 JS 번호를 처리하므로 좋은 기본값입니다.


답변

다음과 같이 할 수 있습니다 :

let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5];

let result = arr.sort((a,b) => {
  if(a == 0 || b == 0)
    return a-b;
  return b-a;
})
console.log(result)

또는 당신은 이것을 할 수 있습니다 :

let arr = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5];

let result = arr.sort().sort((a,b) => {
  if(a > 0 && b > 0)
    return b-a
  return 0
})

console.log(result)