Come posso ordinare un elenco in ordine alfabetico usando jQuery?


233

Sono un po 'fuori dalla mia profondità qui e spero che questo sia effettivamente possibile.

Mi piacerebbe poter chiamare una funzione che ordinerebbe alfabeticamente tutti gli elementi della mia lista.

Ho cercato nell'interfaccia utente di jQuery per l'ordinamento, ma non sembra essere quello. qualche idea?



Dai un'occhiata a Underscore.js o Sugar.js .
Kris Khaira

Risposte:


106

Non hai bisogno di jQuery per fare questo ...

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

Facile da usare...

sortUnorderedList("ID_OF_LIST");

Demo live →


30
Un problema che ho riscontrato con questo approccio è che, poiché è solo il testo che viene spostato, se si associano dati ai nodi DOM utilizzando jQuery.data prima dell'ordinamento, tali associazioni ora puntano a nodi sbagliati dopo l'ordinamento.
Rudismo,

13
Lo spostamento di elementi con innerHTML è una cattiva soluzione perché non sono gli stessi elementi dopo l'ordinamento. Tutti i riferimenti esistenti agli elementi vengono persi. Tutti i listener di eventi associati a JavaScript vengono persi. Sarebbe meglio archiviare gli elementi invece di innerHTML, utilizzare una funzione di ordinamento (vals.sort (funzione (a, b) {return b.innerHTML <a.innerHTML;})) e appendChild per spostare gli elementi.
Gregers

4
Buhuuu innerHTML! Non usarlo. È roba di proprietà Microsoft e non è mai stato riconosciuto dal W3C.
Steve K,

14
IMHO questa è una risposta orribile. È perfettamente possibile riorganizzare i nodi DOM senza serializzarli e deserializzarli di nuovo, e senza distruggere proprietà e / o eventi collegati.
Alnitak,

4
... ma se dovessi usare jQuery, come lo faresti?
Matteo,

332

Qualcosa come questo:

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

Da questa pagina: http://www.onemoretake.com/2009/02/25/sorting-elements-with-jquery/

Il codice sopra ordinerà il tuo elenco non ordinato con ID 'myUL'.

O puoi usare un plugin come TinySort. https://github.com/Sjeiti/TinySort


6
L'ultima riga può essere sostituita con $ (listitems) .appendTo (mylist); ?
Amir,

26
HL Menken ha una citazione che descrive questa soluzione: "Per ogni problema, esiste una soluzione semplice, elegante e sbagliata". Questo processo viene eseguito in tempo O (n ^ 2). Non è evidente con elenchi relativamente brevi, ma su un elenco contenente oltre 100 elementi sono necessari 3-4 secondi per terminare l'ordinamento.
Nathan Strong,

5
@Nathan: Informazioni su "Per ogni problema, esiste una soluzione semplice, elegante e sbagliata". - beh, una soluzione sbagliata non è elegante.
Johann Philipp Strathausen,

18
Qualcosa può essere elegante e intrigante da guardare, ma non riesce ancora. L'eleganza non implica il successo.
Jane Panda,

13
Questa soluzione non è sbagliata. Risponde alla domanda. Il PO non ha specificato che doveva ordinare un elenco di oltre 100 articoli. Se la sua lista non sarà mai più lunga di 100 articoli questa soluzione è perfettamente accettabile. +1 per indicare che la soluzione è lenta, -1 per dichiarare "errata" una soluzione che soddisfa i requisiti.
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;    
}

demo live: http://jsbin.com/eculis/876/edit


15
Questa è la risposta migliore Mi piace anche in una singola linea in questo modo: $(".list li").sort(function(a, b){return ($(b).text()) < ($(a).text());}).appendTo('.list');. Un'osservazione però: .text()dovrebbe essere.text().toUpperCase()
Jules Colle

Sfortunatamente questa soluzione non funziona in Internet Explorer mentre la risposta di Patrick Hecks di seguito funziona in tutti i browser.
patg

8
Attenzione al selettore! ".list li" selezionerà tutti i tag LI discendenti, non solo i figli immediati.
Doug Domeny,

3
@DougDomeny ha ragione. Meglio chiamare $(".list").children(), se possibile, o impostare il selettore con una relazione figlio immediata come:$(".list > li")
mroncetwice,

1
A proposito ecco un link a un violino che ho creato usando questa risposta. Ho impostato il codice come una funzione all-in-one: jsfiddle.net/mroncetwice/t0whh6fL
mroncetwice il

39

Per far funzionare tutto questo con tutti i browser incluso Chrome, devi rendere la funzione di callback di sort () restituita -1,0 o 1.

vedi 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");

2
Tutti gli elementi li non dovrebbero essere rimossi da ul.myList prima di aggiungere gli elementi li ordinati?
Daud,

2
@Daud, non è necessario rimuovere esplicitamente gli elementi LI.
Doug Domeny,

1
L'uso di .localeCompare sarebbe un miglioramento per i caratteri non ASCII.
Doug Domeny,

1
@DougDomeny, perché non è necessario rimuovere esplicitamente gli elementi li?
Bowserm,

3
@bowserm, il metodo appendTo sposta gli elementi DOM anziché copiarli.
Doug Domeny,

31

Se stai usando jQuery puoi farlo:

$(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>

Si noti che la restituzione di 1 e -1 (o 0 e 1) dalla funzione di confronto è assolutamente errata .


7

La soluzione di @ SolutionYogi funziona come un incantesimo, ma sembra che l'utilizzo di $ .each sia meno semplice ed efficiente rispetto agli elenchi direttamente aggiunti:

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

Violino


$ ('# list'). empty () -> mylist.empty () sarebbe meglio. Non è necessario toccare nuovamente il DOM.
Jacob van Lingen,

Assolutamente, l'ho appena risolto!
Buzut,

Questo non funziona in Internet Explorer (testato con la versione 10).
Chad Johnson,

Ho appena testato con IE11 e in effetti non funziona. Ma il codice di SolutionYogi non ha funzionato né in IE11 ... Ha funzionato per te?
Buzut,

1

miglioramento basato sulla risposta di Jeetendra Chauhan

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

perché lo considero un miglioramento:

  1. usando eachper supportare l'esecuzione su più di un ul

  2. l'utilizzo al children('li')posto di ('ul li')è importante perché vogliamo elaborare solo figli diretti e non discendenti

  3. l'utilizzo della funzione freccia è (a,b)=>semplicemente migliore (IE non supportato)

  4. usando la vaniglia innerTextanziché $(a).text()per migliorare la velocità

  5. l'uso della vaniglia localeComparemigliora la velocità in caso di elementi uguali (raro nell'uso nella vita reale)

  6. l'uso appendTo(this)invece di utilizzare un altro selettore farà in modo che anche se il selettore cattura più di un ul, non si rompe nulla


0

Stavo cercando di farlo da solo, e non ero soddisfatto di nessuna delle risposte fornite semplicemente perché, credo, sono tempi quadratici, e ho bisogno di farlo su liste lunghe centinaia di voci.

Ho finito per estendere jquery e la mia soluzione utilizza jquery, ma potrebbe essere facilmente modificata per utilizzare javascript direttamente.

Accedo a ciascun elemento solo due volte ed eseguo un ordinamento linearitmico, quindi penso che dovrebbe funzionare molto più velocemente su grandi set di dati, anche se confesso liberamente che potrei sbagliarmi lì:

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


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/

Qui stiamo spingendo tutti i valori degli lielementi all'interno ulcon specifici id(che abbiamo fornito come argomento di funzione) per array arre ordinarli usando il metodo sort () che è ordinato alfabeticamente per impostazione predefinita. Dopo che la matrice arrè stata ordinata, eseguiamo il ciclo di questa matrice usando il metodo forEach () e sostituiamo semplicemente il contenuto testuale di tutti gli lielementi con il contenuto ordinato

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.