Witam,
mam mały problem - mianowicie mam tablicę obiektów, które mają propety isActive
mogące przyjąć wartość false
/undefined
. Potrzebuję posortować moją tablicę, w kolejności undefined
-> false
(np. [undefined, false, false, undefined]
-> [undefined, undefined, false, false]
). Jak porównywać te 2 wartości?
Ogólnie funkcja sort przyjmuje callback, który pozwoli ci porównać:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
wydaje się łatwe. Teoretycznie wystarczyłoby porównać coś z undefined i jeśli tak, to stwierdzić, że coś jest mniejsze/większe zwracając 1 albo -1. Teoretycznie.
Jednak z jakiegoś powodu JS traktuje undefined
inaczej niż inne wartości przy sortowaniu. Taki kawałek kodu próbowałem:
const VALUE = undefined;
const arr = [10, 30, 89, 2, VALUE, 3, VALUE];
arr.sort((a, b) => {
if (a === VALUE) {
return -1;
}
if (b === VALUE) {
return 1;
}
return a - b;
})
console.log(arr);
I teraz, co ciekawe, jeśli za VALUE podstawimy coś innego, np.
const VALUE = 'foo'; // albo np. const VALUE = null;
to wyjdzie nam ta wartość na początku:
['foo', 'foo', 2, 3, 10, 30, 89]
[null, null, 2, 3, 10, 30, 89]
przy undefined
mamy inaczej:
const VALUE = undefined;
dałoby
[ 2, 3, 10, 30, 89, undefined, undefined ]
W sumie niezły WTF, chociaż opisany przez MDN:
all undefined elements are sorted to the end of the array, with no call to compareFunction).
Czyli język JS nie pozwala bezpośrednio na to, co chcesz zrobić, choć możesz to jakoś spróbować obejść, np. po sortowaniu zabrać undefined
z końca i wstawić na początek. Albo zamiast undefined używać null itp.
Najprostsze rozwiązanie na metodę sort jakie przychodzi mi do głowy to użycie reverse
:D
const values = [undefined, false, undefined, false, true, true, false];
const sortA = [...values].sort((a, b) => b - a);
const sortB = [...values].sort((a, b) => b - a).reverse();
console.dir(sortA); // true, true, false, false, false, undefined, undefined
console.dir(sortB); // undefined, undefined, false, false, false, true, true
Można też spróbować napisać własny algorytm do sortowania, który nie ma tego problemu.
const f = { isActive: false }
const u = { isActive: undefined };
const list = [
{...u, id: 1},
{...f, id: 2},
{...f, id: 3},
{...u, id: 4},
];
// ^ przygotowanie danych
// -----
// v implementacja rozwiązania
list.sort(s => s.isActive === undefined ? -1 : 1);
console.log(list)
Najprościej tak
LukeJL napisał(a):
Czyli język JS nie pozwala bezpośrednio na to, co chcesz zrobić, choć możesz to jakoś spróbować obejść, np. po sortowaniu zabrać
undefined
z końca i wstawić na początek. Albo zamiast undefined używać null itp.
Nie zaraz język, tylko funkcja w bibliotece standardowej. Nie wprowadzaj w błąd.
LukeJL napisał(a):
Ale to cześć języka. AFAIK. Bo można się przejechać. Np. console.log nie jest częścią JSa. Ale tablice i ich metody to (o ile dobrze wiem) cześć specyfikacji EcmaScript wiec cześć JSa dla mnie.
Ale mówić Czyli język JS nie pozwala bezpośrednio na to, co chcesz zrobić
to nie prawda, bo możesz w tym języku napisać sobie .sort()
jaki tylko chcesz, a potem wsadzić to w Array.prototype.sort
jak chcesz.