JavaScript sortuje tablicę według dwóch pól


88
grouperArray.sort(function (a, b) {
    var aSize = a.gsize;
    var bSize = b.gsize;
    var aLow = a.glow;
    var bLow = b.glow;
    console.log(aLow + " | " + bLow);      
    return (aSize < bSize) ? -1 : (aSize > bSize) ? 1 : 0;
});

Zatem powyższy kod sortuje tablicę według gsize - od najmniejszej do największej. Działa dobrze. Ale jeśli gsize jest taki sam, chciałbym, żeby to sortował według blasku.

Dzięki.


Funkcja sort reaguje na wynik dodatni, ujemny lub zerowy. więc możesz po prostu napisać: "return aSize - bSize". będzie to prostszy i bardziej czytelny kod.

Odpowiedzi:


107
grouperArray.sort(function (a, b) {
    var aSize = a.gsize;
    var bSize = b.gsize;
    var aLow = a.glow;
    var bLow = b.glow;
    console.log(aLow + " | " + bLow);

    if(aSize == bSize)
    {
        return (aLow < bLow) ? -1 : (aLow > bLow) ? 1 : 0;
    }
    else
    {
        return (aSize < bSize) ? -1 : 1;
    }
});

170
grouperArray.sort(function (a, b) {   
    return a.gsize - b.gsize || a.glow - b.glow;
});

krótsza wersja


świetny skrót! pomógł mi położyć bardziej kompleksowe rozwiązanie razem .. stackoverflow.com/questions/6101475/...
Joseph Poirier

3
Ładnie i czysto! Jedyne, co działa tylko dla liczb.
Afanasii Kurakin

Czy możesz wyjaśnić tę logikę?!. U mnie zadziałało, sort an array with a key's value firsta potemsort the result with another key's value
KTM

1
@KTM Logika jest następująca: jeśli oba gsize są równe, to pierwsza część warunku jest równa 0, co jest uważane za fałsz, a druga część warunku jest wykonywana.
Scalpweb

@Scalpweb Tak :) więc to działa, aby posortować tablicę z dowolną liczbą kluczy jeden po drugim, prawda ?! Niezła sztuczka
KTM


14

Zdaję sobie sprawę, że pytano o to jakiś czas temu, ale pomyślałem, że dodam swoje rozwiązanie.

Ta funkcja dynamicznie generuje metody sortowania. po prostu podaj każdą możliwą do sortowania nazwę właściwości podrzędnej, poprzedzoną znakiem +/-, aby wskazać kolejność rosnącą lub malejącą. Super do ponownego użycia i nie musi nic wiedzieć o utworzonej strukturze danych. Można to uczynić idiotą - ale nie wydaje się konieczne.

function getSortMethod(){
    var _args = Array.prototype.slice.call(arguments);
    return function(a, b){
        for(var x in _args){
            var ax = a[_args[x].substring(1)];
            var bx = b[_args[x].substring(1)];
            var cx;

            ax = typeof ax == "string" ? ax.toLowerCase() : ax / 1;
            bx = typeof bx == "string" ? bx.toLowerCase() : bx / 1;

            if(_args[x].substring(0,1) == "-"){cx = ax; ax = bx; bx = cx;}
            if(ax != bx){return ax < bx ? -1 : 1;}
        }
    }
}

przykład użycia:

items.sort (getSortMethod ('- cena', '+ priorytet', '+ nazwa'));

posortowałoby to itemsod najniższej do pricepierwszej, z powiązaniami prowadzącymi do pozycji o najwyższej priority. dalsze więzi są zrywane przez przedmiotname

gdzie elementy to tablica taka jak:

var items = [
    { name: "z - test item", price: "99.99", priority: 0, reviews: 309, rating: 2 },
    { name: "z - test item", price: "1.99", priority: 0, reviews: 11, rating: 0.5 },
    { name: "y - test item", price: "99.99", priority: 1, reviews: 99, rating: 1 },
    { name: "y - test item", price: "0", priority: 1, reviews: 394, rating: 3.5 },
    { name: "x - test item", price: "0", priority: 2, reviews: 249, rating: 0.5 } ...
];

demo na żywo: http://gregtaff.com/misc/multi_field_sort/

EDYCJA: Naprawiono problem z Chrome.


To jest genialne
Azure

Genialna odpowiedź!
Marius

dla maszynopisu (aby nie uzyskać error TS2554: Expected 0 arguments, but got ..) użyj składni tutaj: stackoverflow.com/a/4116634/5287221
Chananel P

6

Spodziewam się, że operator trójskładnikowy((aSize < bSize) ? -1 : (aSize > bSize) ? 1 : 0;) cię pomylił. Powinieneś sprawdzić link, aby lepiej go zrozumieć.

Do tego czasu, oto twój kod wydmuchany w pełni if ​​/ else.

grouperArray.sort(function (a, b) {
    if (a.gsize < b.gsize)
    {
        return -1;
    }
    else if (a.gsize > b.gsize)
    {
        return 1;
    }
    else
    {
        if (a.glow < b.glow)
        {
            return -1;
        }
        else if (a.glow > b.glow)
        {
            return 1;
        }
        return 0;
    }
});

6

Oto implementacja dla tych, którzy mogą chcieć czegoś bardziej ogólnego, który działałby z dowolną liczbą pól.

Array.prototype.sortBy = function (propertyName, sortDirection) {

    var sortArguments = arguments;
    this.sort(function (objA, objB) {

        var result = 0;
        for (var argIndex = 0; argIndex < sortArguments.length && result === 0; argIndex += 2) {

            var propertyName = sortArguments[argIndex];
            result = (objA[propertyName] < objB[propertyName]) ? -1 : (objA[propertyName] > objB[propertyName]) ? 1 : 0;

            //Reverse if sort order is false (DESC)
            result *= !sortArguments[argIndex + 1] ? 1 : -1;
        }
        return result;
    });

}

Zasadniczo możesz określić dowolną liczbę nazw właściwości / kierunku sortowania:

var arr = [{
  LastName: "Doe",
  FirstName: "John",
  Age: 28
}, {
  LastName: "Doe",
  FirstName: "Jane",
  Age: 28
}, {
  LastName: "Foo",
  FirstName: "John",
  Age: 30
}];

arr.sortBy("LastName", true, "FirstName", true, "Age", false);
//Will return Jane Doe / John Doe / John Foo

arr.sortBy("Age", false, "LastName", true, "FirstName", false);
//Will return John Foo / John Doe / Jane Doe

3
grouperArray.sort(function (a, b) {
  var aSize = a.gsize;
  var bSize = b.gsize;
  var aLow = a.glow;
  var bLow = b.glow;
  console.log(aLow + " | " + bLow);      
  return (aSize < bSize) ? -1 : (aSize > bSize) ? 1 : ( (aLow < bLow ) ? -1 : (aLow > bLow ) ? 1 : 0 );
});

3
grouperArray.sort(function (a, b) {
     var aSize = a.gsize;     
     var bSize = b.gsize;     
     var aLow = a.glow;
     var bLow = b.glow;
     console.log(aLow + " | " + bLow);
     return (aSize < bSize) ? -1 : (aSize > bSize) ? 1 : (aLow < bLow) ? -1 : (aLow > bLow) ? 1 : 0); }); 

3

Oto implementacja, która używa rekurencji do sortowania według dowolnej liczby pól sortowania od 1 do nieskończoności. Przekazujesz mu tablicę wyników, która jest tablicą obiektów wynikowych do sortowania, oraz tablicę sortów, która jest tablicą obiektów sortowania definiujących sortowanie. Każdy obiekt sortowania musi mieć klucz „select” dla nazwy klucza, według którego sortuje, oraz klucz „order”, który jest łańcuchem oznaczającym „rosnąco” lub „malejąco”.

sortMultiCompare = (a, b, sorts) => {
    let select = sorts[0].select
    let order = sorts[0].order
    if (a[select] < b[select]) {
        return order == 'ascending' ? -1 : 1
    } 
    if (a[select] > b[select]) {
        return order == 'ascending' ? 1 : -1
    }
    if(sorts.length > 1) {
        let remainingSorts = sorts.slice(1)
        return this.sortMultiCompare(a, b, remainingSorts)
    }
    return 0
}

sortResults = (results, sorts) => {
    return results.sort((a, b) => {
        return this.sortMultiCompare(a, b, sorts)
    })
}

// example inputs
const results = [
    {
        "LastName": "Doe",
        "FirstName": "John",
        "MiddleName": "Bill"
    },
    {
        "LastName": "Doe",
        "FirstName": "Jane",
        "MiddleName": "Bill"
    },
    {
        "LastName": "Johnson",
        "FirstName": "Kevin",
        "MiddleName": "Bill"
    }
]

const sorts = [
    {
        "select": "LastName",
        "order": "ascending"
    },
    {
        "select": "FirstName",
        "order": "ascending"
    },
    {
        "select": "MiddleName",
        "order": "ascending"
    }    
]

// call the function like this:
let sortedResults = sortResults(results, sorts)

2

Dynamiczny sposób na zrobienie tego za pomocą WIELU klawiszy:

  • filtruj unikalne wartości z każdego sortowania kolumny / klucza
  • uporządkować lub odwrócić
  • dodaj wagi szerokość zeropad dla każdego obiektu na podstawie wartości kluczy indexOf (value)
  • sortuj według obliczonych wag

wprowadź opis obrazu tutaj

Object.defineProperty(Array.prototype, 'orderBy', {
value: function(sorts) { 
    sorts.map(sort => {            
        sort.uniques = Array.from(
            new Set(this.map(obj => obj[sort.key]))
        );

        sort.uniques = sort.uniques.sort((a, b) => {
            if (typeof a == 'string') {
                return sort.inverse ? b.localeCompare(a) : a.localeCompare(b);
            }
            else if (typeof a == 'number') {
                return sort.inverse ? (a < b) : (a > b ? 1 : 0);
            }
            else if (typeof a == 'boolean') {
                let x = sort.inverse ? (a === b) ? 0 : a? -1 : 1 : (a === b) ? 0 : a? 1 : -1;
                return x;
            }
            return 0;
        });
    });

    const weightOfObject = (obj) => {
        let weight = "";
        sorts.map(sort => {
            let zeropad = `${sort.uniques.length}`.length;
            weight += sort.uniques.indexOf(obj[sort.key]).toString().padStart(zeropad, '0');
        });
        //obj.weight = weight; // if you need to see weights
        return weight;
    }

    this.sort((a, b) => {
        return weightOfObject(a).localeCompare( weightOfObject(b) );
    });

    return this;
}
});

Posługiwać się:

// works with string, number and boolean
let sortered = your_array.orderBy([
    {key: "type", inverse: false}, 
    {key: "title", inverse: false},
    {key: "spot", inverse: false},
    {key: "internal", inverse: true}
]);

wprowadź opis obrazu tutaj


1

To jest to, czego używam

function sort(a, b) {
    var _a = "".concat(a.size, a.glow);
    var _b = "".concat(b.size, b.glow);
    return _a < _b;
}

połącz oba elementy jako ciąg, a zostaną one posortowane według wartości ciągu. Jeśli chcesz, możesz zawinąć _a i _b parseInt, aby porównać je jako liczby, jeśli wiesz, że będą numeryczne.


1

Oto rozwiązanie dla przypadku, gdy masz priorytetowy klucz sortowania, który może nie istnieć w niektórych konkretnych elementach, więc musisz sortować według kluczy rezerwowych.

Przykład danych wejściowych ( id2 to priorytet sortowania klucza):

const arr = [
    {id: 1},
    {id: 2, id2: 3},
    {id: 4},
    {id: 3},
    {id: 10, id2: 2},
    {id: 7},
    {id: 6, id2: 1},
    {id: 5},
    {id: 9, id2: 2},
    {id: 8},
];

Wynik powinien być:

[ { id: 6, id2: 1 },
  { id: 9, id2: 2 },
  { id: 10, id2: 2 },
  { id: 2, id2: 3 },
  { id: 1 },
  { id: 3 },
  { id: 4 },
  { id: 5 },
  { id: 7 },
  { id: 8 } ]

Funkcja komparatora będzie wyglądać następująco:

arr.sort((a,b) => {
  if(a.id2 || b.id2) {
    if(a.id2 && b.id2) {
      if(a.id2 === b.id2) {
        return a.id - b.id;
      }
      return a.id2 - b.id2;
    }
    return a.id2 ? -1 : 1;
  }
  return a.id - b.id
});

PS W przypadku, gdy .id z .id2 może być zerami, rozważ użycie typeof.


0
grouperArray.sort(
  function(a,b){return a.gsize == b.gsize ? a.glow - b.glow : a.gsize - b.gsize}
);

0
grouperArray.sort(function (a, b) {
    var aSize = a.gsize;
    var bSize = b.gsize;
    if (aSize !== aSize)
        return aSize - bSize;
    return a.glow - b.glow;
});

nie testowane, ale myślę, że to powinno działać.


0

W moim przypadku sortuję listę powiadomień według parametru „ważne” i „daty”

  • krok 1: filtruję powiadomienia według „ważnych” i nieważnych

    let importantNotifications = notifications.filter(
            (notification) => notification.isImportant);
    
      let unImportantNotifications = notifications.filter(
            (notification) => !notification.isImportant);
    
  • krok 2: sortuję je według daty

      sortByDate = (notifications) => {
      return notifications.sort((notificationOne, notificationTwo) => {
        return notificationOne.date - notificationTwo.date;
      });
    };
    
  • krok 3: scal je

    [
        ...this.sortByDate(importantNotifications),
        ...this.sortByDate(unImportantNotifications),
      ];
    
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.