Javascript-Sortierarray nach zwei Feldern

84
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;
});

Der obige Code sortiert das Array also nach gsize - vom kleinsten zum größten. Es funktioniert gut. Aber wenn die Größe gleich ist, möchte ich, dass sie nach Glühen sortiert wird.

Vielen Dank.

Kennzeichen
quelle
Die Sortierfunktion reagiert auf ein positives, negatives oder Null-Ergebnis. Sie können also einfach schreiben: "return aSize - bSize". Es wird einfacher und lesbarer Code sein.

Antworten:

102
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;
    }
});
Chris Eberle
quelle
152
grouperArray.sort(function (a, b) {   
    return a.gsize - b.gsize || a.glow - b.glow;
});

kürzere Version

anmorozov23
quelle
tolle Abkürzung! hat mir geholfen, eine komplexere Lösung zusammenzustellen .. stackoverflow.com/questions/6101475/…
Joseph Poirier
3
Schön und sauber! Das einzige, was es nur für Zahlen funktioniert.
Afanasii Kurakin
Können Sie die Logik hier erklären?!. Es hat bei mir funktioniert sort an array with a key's value firstund dannsort the result with another key's value
KTM
1
@KTM Die Logik lautet wie folgt: Wenn beide gsize gleich sind, ist der erste Teil der Bedingung gleich 0, was als falsch betrachtet wird, und der zweite Teil der Bedingung wird ausgeführt.
Scalpweb
@Scalpweb Ja :) Das funktioniert also, um ein Array mit einer beliebigen Anzahl von Schlüsseln nacheinander zu sortieren, oder?! Schöner Trick
KTM
31
grouperArray.sort((a, b) => a.gsize - b.gsize || a.glow - b.glow);

Noch kürzere Version mit Pfeilsyntax!

Vinorth
quelle
3
Das prägnanteste und erweiterbarste, perfekteste!
Laurent
13

Mir ist klar, dass dies vor einiger Zeit gefragt wurde, aber ich dachte, ich würde meine Lösung hinzufügen.

Diese Funktion generiert Sortiermethoden dynamisch. Geben Sie einfach jeden sortierbaren untergeordneten Eigenschaftsnamen an, dem +/- vorangestellt ist, um die aufsteigende oder absteigende Reihenfolge anzuzeigen. Super wiederverwendbar, und es muss nichts über die Datenstruktur wissen, die Sie zusammengestellt haben. Könnte idiotensicher gemacht werden - scheint aber nicht notwendig.

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;}
        }
    }
}

Anwendungsbeispiel:

items.sort (getSortMethod ('- Preis', '+ Priorität', '+ Name'));

Dies würde itemsmit dem niedrigsten pricezuerst sortieren , wobei die Bindungen zu dem Gegenstand mit dem höchsten gehen würdenpriority . Weitere Bindungen werden durch den Gegenstand unterbrochenname

Dabei ist items ein Array wie:

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 } ...
];

Live-Demo: http://gregtaff.com/misc/multi_field_sort/

BEARBEITEN: Problem mit Chrome behoben.

Nihlton
quelle
Das ist brilliant
Azure
Geniale Antwort!
Marius
6

Ich gehe davon aus, dass der ternäre Operator ((aSize < bSize) ? -1 : (aSize > bSize) ? 1 : 0;)Sie verwirrt hat. Sie sollten den Link überprüfen, um ihn besser zu verstehen.

Bis dahin ist hier Ihr Code vollständig ausgeblasen, wenn / sonst.

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;
    }
});
John Green
quelle
6

Hier ist eine Implementierung für diejenigen, die etwas allgemeineres wünschen, das mit einer beliebigen Anzahl von Feldern funktioniert.

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;
    });

}

Grundsätzlich können Sie eine beliebige Anzahl von Eigenschaftsnamen / Sortierrichtungen angeben:

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
The_Black_Smurf
quelle
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 );
});
Silex
quelle
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); }); 
Tim Williams
quelle
3

Hier ist eine Implementierung, die Rekursion verwendet, um nach einer beliebigen Anzahl von Sortierfeldern von 1 bis unendlich zu sortieren. Sie übergeben ihm ein Ergebnisarray, das ein Array von zu sortierenden Ergebnisobjekten ist, und ein Sortierarray, das ein Array von Sortierobjekten ist, die die Sortierung definieren. Jedes Sortierobjekt muss einen "Auswahl" -Schlüssel für den Schlüsselnamen haben, nach dem es sortiert, und einen "Ordnungs" -Schlüssel, der eine Zeichenfolge ist, die "aufsteigend" oder "absteigend" anzeigt.

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)
Benjamin Portman
quelle
1

Hier ist die Lösung für den Fall, dass Sie einen Prioritätssortierschlüssel haben, der in bestimmten Elementen möglicherweise nicht vorhanden ist. Daher müssen Sie nach Fallback-Schlüsseln sortieren.

Ein Beispiel für Eingabedaten ( id2 ist der Prioritätssortierschlüssel):

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},
];

Und die Ausgabe sollte sein:

[ { 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 } ]

Die Komparatorfunktion lautet wie folgt:

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 Wenn .id von .id2 Nullen sein kann, sollten Sie die Verwendung in Betracht ziehen typeof.

Deliaz
quelle
1

Ein dynamischer Weg, dies mit mehreren Tasten zu tun:

  • Filtern Sie eindeutige Werte aus jeder Spalte / jedem Schlüssel der Sortierung
  • in Ordnung bringen oder umkehren
  • Fügen Sie für jedes Objekt Gewichte mit der Breite Null hinzu, basierend auf den Schlüsselwerten von indexOf (value)
  • sortieren mit caclutated Gewichten

Geben Sie hier die Bildbeschreibung ein

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;
}
});

Verwenden:

// 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}
]);

Geben Sie hier die Bildbeschreibung ein

Leonardo Filipe
quelle
0
grouperArray.sort(
  function(a,b){return a.gsize == b.gsize ? a.glow - b.glow : a.gsize - b.gsize}
);
ic3b3rg
quelle
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;
});

nicht getestet, aber ich denke das sollte funktionieren.

Xander
quelle
0

Das benutze ich

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

Konzentrieren Sie die beiden Elemente als Zeichenfolge und sie werden nach einem Zeichenfolgenwert sortiert. Wenn Sie möchten, können Sie _a und _b mit parseInt umschließen, um sie als Zahlen zu vergleichen, wenn Sie wissen, dass sie numerisch sind.

Blockloop
quelle