Если вы заботитесь об эффективности, возможно, быстрее всего сначала отфильтровать нули . Вы не хотите sort
тратить время, даже глядя на них, не говоря уже о добавлении дополнительной работы к вашему обратному вызову сравнения для обработки этого особого случая.
Особенно, если вы ожидаете значительное количество нулей, один проход по данным для их фильтрации должен быть намного лучше, чем выполнять более крупную O (N log N) сортировку, которая будет смотреть на каждый ноль несколько раз.
Вы можете эффективно добавлять правильное количество нулей после того, как вы закончите.
Также легко прочитать полученный код. Я использовал TypedArray, потому что он эффективен и упрощает сортировку чисел . Но вы можете использовать эту технику с обычным массивом, используя стандартную идиому (a,b)=>a-b
для .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
, зациклите его и поменяйте местами нули в начале массива. Это займет один проход над вашими данными.
Затем используйте .subarray()
для получения нового представления TypedArray ненулевых элементов того же базового ArrayBuffer. Сортировка, в результате которой вы получите полный массив с нулевым началом и отсортированным хвостом, причем сортировка всегда будет рассматривать только ненулевые элементы.
Я не видел функции разделения в методах Array или TypedArray, но я почти не знаю JavaScript. При хорошем JIT цикл не должен быть намного хуже, чем встроенный метод. (Особенно, когда этот метод включает в себя функцию обратного вызова .filter
, и если он не используется realloc
под капотом для сжатия, он должен выяснить, сколько памяти выделить, прежде чем он фактически отфильтровывается).
Я использовал обычный массив .filter()
перед преобразованием в TypedArray. Если ваши входные данные уже являются TypedArray, у вас нет этой проблемы, и эта стратегия становится еще более привлекательной.