Wie kann ich eine Liste mit jQuery alphabetisch sortieren?

233

Ich bin hier etwas überfordert und hoffe, dass dies tatsächlich möglich ist.

Ich möchte eine Funktion aufrufen können, die alle Elemente in meiner Liste alphabetisch sortiert.

Ich habe die jQuery-Benutzeroberfläche nach Sortierung durchsucht, aber das scheint es nicht zu sein. Irgendwelche Gedanken?

Shog9
quelle
Schauen Sie sich Underscore.js oder Sugar.js an .
Kris Khaira

Antworten:

106

Sie benötigen dazu nicht jQuery ...

function sortUnorderedList(ul, sortDescending) {
  if(typeof ul == "string")
    ul = document.getElementById(ul);

  // Idiot-proof, remove if you want
  if(!ul) {
    alert("The UL object is null!");
    return;
  }

  // Get the list items and setup an array for sorting
  var lis = ul.getElementsByTagName("LI");
  var vals = [];

  // Populate the array
  for(var i = 0, l = lis.length; i < l; i++)
    vals.push(lis[i].innerHTML);

  // Sort it
  vals.sort();

  // Sometimes you gotta DESC
  if(sortDescending)
    vals.reverse();

  // Change the list on the page
  for(var i = 0, l = lis.length; i < l; i++)
    lis[i].innerHTML = vals[i];
}

Einfach zu verwenden...

sortUnorderedList("ID_OF_LIST");

Live-Demo →

Josh Stodola
quelle
28
Ein Problem, das ich bei diesem Ansatz festgestellt habe, besteht darin, dass diese Zuordnungen nach dem Sortieren auf die falschen Knoten verweisen, da nur der Text verschoben wird. Wenn Sie vor dem Sortieren Daten mit jQuery.data den DOM-Knoten zuordnen.
Rudismus
12
Das Verschieben von Elementen mit innerHTML ist eine schlechte Lösung, da sie nach dem Sortieren nicht dieselben Elemente sind. Alle vorhandenen Verweise auf die Elemente gehen verloren. Alle an JavaScript gebundenen Ereignis-Listener gehen verloren. Es ist besser, die Elemente anstelle von innerHTML zu speichern, eine Sortierfunktion (vals.sort (Funktion (a, b) {return b.innerHTML <a.innerHTML;})) und appendChild zum Verschieben von Elementen zu verwenden.
Gregers
3
Buhuuu innerHTML! Benutze das nicht. Es handelt sich um Microsoft Proprietary-Produkte, die vom W3C nie anerkannt wurden.
Steve K
13
IMHO ist das eine schreckliche Antwort. Es ist durchaus möglich, DOM-Knoten neu anzuordnen, ohne sie zu serialisieren und erneut zu deserialisieren und ohne angehängte Eigenschaften und / oder Ereignisse zu zerstören.
Alnitak
3
... aber wenn Sie jQuery verwenden würden, wie würden Sie es tun?
Matthew
332

Etwas wie das:

var mylist = $('#myUL');
var listitems = mylist.children('li').get();
listitems.sort(function(a, b) {
   return $(a).text().toUpperCase().localeCompare($(b).text().toUpperCase());
})
$.each(listitems, function(idx, itm) { mylist.append(itm); });

Von dieser Seite: http://www.onemoretake.com/2009/02/25/sorting-elements-with-jquery/

Der obige Code sortiert Ihre ungeordnete Liste mit der ID 'myUL'.

ODER Sie können ein Plugin wie TinySort verwenden. https://github.com/Sjeiti/TinySort

SolutionYogi
quelle
6
Kann die letzte Zeile durch $ (listitems) .appendTo (mylist) ersetzt werden? ?
Amir
26
HL Menken hat ein Zitat, das diese Lösung beschreibt: "Für jedes Problem gibt es eine Lösung, die einfach, elegant und falsch ist." Dieser Prozess läuft in O (n ^ 2) Zeit. Bei relativ kurzen Listen fällt dies nicht auf, aber bei einer Liste mit über 100 Elementen dauert es 3-4 Sekunden, bis die Sortierung abgeschlossen ist.
Nathan Strong
5
@ Nathan: Über "Für jedes Problem gibt es eine Lösung, die einfach, elegant und falsch ist." - Nun, eine falsche Lösung ist nicht elegant.
Johann Philipp Strathausen
18
Etwas kann elegant und faszinierend sein, aber dennoch scheitern. Eleganz bedeutet keinen Erfolg.
Jane Panda
13
Diese Lösung ist nicht falsch. Es beantwortet die Frage. Das OP gab nicht an, dass er eine Liste mit mehr als 100 Elementen sortieren musste. Wenn seine Liste niemals länger als 100 Elemente sein wird, ist diese Lösung vollkommen akzeptabel. +1 für den Hinweis, dass die Lösung langsam ist, -1 für die Deklaration einer Lösung, die die Anforderungen erfüllt, als "falsch".
Samurai Soul
94
$(".list li").sort(asc_sort).appendTo('.list');
//$("#debug").text("Output:");
// accending sort
function asc_sort(a, b){
    return ($(b).text()) < ($(a).text()) ? 1 : -1;    
}

// decending sort
function dec_sort(a, b){
    return ($(b).text()) > ($(a).text()) ? 1 : -1;    
}

Live-Demo: http://jsbin.com/eculis/876/edit

Jeetendra Chauhan
quelle
15
Dies ist die beste Antwort. Ich mag es sogar in einer einzigen Zeile wie folgt : $(".list li").sort(function(a, b){return ($(b).text()) < ($(a).text());}).appendTo('.list');. Eine Bemerkung: .text()sollte sein.text().toUpperCase()
Jules Colle
Leider funktioniert diese Lösung im IE nicht, während die unten stehende Antwort von PatrickHecks in allen Browsern funktioniert.
Patg
8
Vorsicht vor dem Selektor! ".list li" wählt alle absteigenden LI-Tags aus, nicht nur die unmittelbaren untergeordneten Elemente.
Doug Domeny
3
@ DougDomeny ist richtig. $(".list").children()Wenn möglich, rufen Sie besser an oder richten Sie den Selektor mit einer unmittelbaren Kinderbeziehung wie$(".list > li")
mroncetwice
1
Übrigens: Hier ist ein Link zu einer Geige, die ich mit dieser Antwort gemacht habe. Ich habe den Code als All-in-One-Funktion eingerichtet: jsfiddle.net/mroncetwice/t0whh6fL
mroncetwice
39

Damit dies mit allen Browsern einschließlich Chrome funktioniert, muss die Rückruffunktion von sort () -1,0 oder 1 zurückgeben.

siehe http://inderpreetsingh.com/2010/12/01/chromes-javascript-sort-array-function-is-different-yet-proper/

function sortUL(selector) {
    $(selector).children("li").sort(function(a, b) {
        var upA = $(a).text().toUpperCase();
        var upB = $(b).text().toUpperCase();
        return (upA < upB) ? -1 : (upA > upB) ? 1 : 0;
    }).appendTo(selector);
}
sortUL("ul.mylist");
PatrickHeck
quelle
2
Sollten nicht alle li-Elemente aus ul.myList entfernt werden, bevor die sortierten li-Elemente angehängt werden?
Daud
2
@Daud, die LI-Elemente müssen nicht explizit entfernt werden.
Doug Domeny
1
Die Verwendung von .localeCompare wäre eine Verbesserung für Nicht-ASCII-Zeichen.
Doug Domeny
1
@DougDomeny, warum müssen die li-Elemente nicht explizit entfernt werden?
Bowserm
3
@bowserm, die appendTo-Methode verschiebt die DOM-Elemente, anstatt sie zu kopieren.
Doug Domeny
31

Wenn Sie jQuery verwenden, können Sie dies tun:

$(function() {

  var $list = $("#list");

  $list.children().detach().sort(function(a, b) {
    return $(a).text().localeCompare($(b).text());
  }).appendTo($list);

});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<ul id="list">
  <li>delta</li>
  <li>cat</li>
  <li>alpha</li>
  <li>cat</li>
  <li>beta</li>
  <li>gamma</li>
  <li>gamma</li>
  <li>alpha</li>
  <li>cat</li>
  <li>delta</li>
  <li>bat</li>
  <li>cat</li>
</ul>

Beachten Sie, dass die Rückgabe von 1 und -1 (oder 0 und 1) von der Vergleichsfunktion absolut falsch ist .

Salman A.
quelle
7

@ SolutionYogis Antwort funktioniert wie ein Zauber, aber es scheint, dass die Verwendung von $ .each weniger einfach und effizient ist als das direkte Anhängen von Listenelementen:

var mylist = $('#list');
var listitems = mylist.children('li').get();

listitems.sort(function(a, b) {
   return $(a).text().toUpperCase().localeCompare($(b).text().toUpperCase());
})

mylist.empty().append(listitems);

Geige

Buzut
quelle
$ ('# list'). empty () -> mylist.empty () wäre besser. Sie müssen das DOM nicht erneut berühren.
Jacob van Lingen
Absolut, ich habe es gerade behoben!
Buzut
Dies funktioniert nicht in Internet Explorer (getestet mit Version 10).
Chad Johnson
Ich habe gerade mit IE11 getestet und tatsächlich funktioniert es nicht. Aber der Code von SolutionYogi funktionierte auch unter IE11 nicht… Hat das bei Ihnen funktioniert?
Buzut
1

Verbesserung basierend auf Jeetendra Chauhans Antwort

$('ul.menu').each(function(){
    $(this).children('li').sort((a,b)=>a.innerText.localeCompare(b.innerText)).appendTo(this);
});

warum ich es für eine Verbesserung halte:

  1. Verwenden each, um das Laufen auf mehr als einer Ul zu unterstützen

  2. Verwenden von children('li')anstelle von ('ul li')ist wichtig, da wir nur direkte Kinder und keine Nachkommen verarbeiten möchten

  3. Die Verwendung der Pfeilfunktion (a,b)=>sieht einfach besser aus (IE wird nicht unterstützt).

  4. Verwenden Sie Vanille innerTextanstelle $(a).text()zur Geschwindigkeitsverbesserung

  5. Die Verwendung von Vanille localeCompareverbessert die Geschwindigkeit bei gleichen Elementen (selten im realen Gebrauch).

  6. Verwendung appendTo(this)stattdessen einen anderen Wähler der Verwendung dafür sorgen, dass auch wenn die Wähler Fänge mehr als eine ul noch nichts bricht

Oriadam
quelle
0

Ich habe versucht, dies selbst zu tun, und ich war mit keiner der Antworten zufrieden, nur weil ich glaube, dass es sich um eine quadratische Zeit handelt, und ich muss dies auf Listen mit Hunderten von Elementen tun.

Am Ende habe ich jquery erweitert, und meine Lösung verwendet jquery, könnte aber leicht geändert werden, um direktes Javascript zu verwenden.

Ich greife nur zweimal auf jedes Element zu und führe eine linearithmische Sortierung durch. Ich denke, dies sollte sich bei großen Datenmengen als viel schneller herausstellen, obwohl ich frei gestehe, dass ich mich dort irren könnte:

sortList: function() {
   if (!this.is("ul") || !this.length)
      return
   else {
      var getData = function(ul) {
         var lis     = ul.find('li'),
             liData  = {
               liTexts : []
            }; 

         for(var i = 0; i<lis.length; i++){
             var key              = $(lis[i]).text().trim().toLowerCase().replace(/\s/g, ""),
             attrs                = lis[i].attributes;
             liData[key]          = {},
             liData[key]['attrs'] = {},
             liData[key]['html']  = $(lis[i]).html();

             liData.liTexts.push(key);

             for (var j = 0; j < attrs.length; j++) {
                liData[key]['attrs'][attrs[j].nodeName] = attrs[j].nodeValue;
             }
          }

          return liData;
       },

       processData = function (obj){
          var sortedTexts = obj.liTexts.sort(),
              htmlStr     = '';

          for(var i = 0; i < sortedTexts.length; i++){
             var attrsStr   = '',
                 attributes = obj[sortedTexts[i]].attrs;

             for(attr in attributes){
                var str = attr + "=\'" + attributes[attr] + "\' ";
                attrsStr += str;
             }

             htmlStr += "<li "+ attrsStr + ">" + obj[sortedTexts[i]].html+"</li>";
          }

          return htmlStr;

       };

       this.html(processData(getData(this)));
    }
}
Macken
quelle
0

HTML

<ul id="list">
    <li>alpha</li>
    <li>gamma</li>
    <li>beta</li>
</ul>

JavaScript

function sort(ul) {
    var ul = document.getElementById(ul)
    var liArr = ul.children
    var arr = new Array()
    for (var i = 0; i < liArr.length; i++) {
        arr.push(liArr[i].textContent)
    }
    arr.sort()
    arr.forEach(function(content, index) {
        liArr[index].textContent = content
    })
}

sort("list")

JSFiddle Demo https://jsfiddle.net/97oo61nw/

Hier werden alle Werte von liElementen ulmit einem bestimmten Element id(das wir als Funktionsargument angegeben haben) in das Array verschoben arrund mit der Methode sort () sortiert, die standardmäßig alphabetisch sortiert ist. Nachdem das Array arrsortiert wurde, werden wir dieses Array mit der forEach () -Methode durchlaufen und ersetzen einfach den Textinhalt aller liElemente durch sortierten Inhalt

Mikhail
quelle