Как я могу отсортировать список в алфавитном порядке, используя jQuery?

233

Я немного не в себе и надеюсь, что это действительно возможно.

Я хотел бы иметь возможность вызывать функцию, которая сортирует все элементы в моем списке в алфавитном порядке.

Я просматривал jQuery UI для сортировки, но это не так. Есть предположения?

Shog9
источник
Проверьте Underscore.js или Sugar.js .
Крис Хайра

Ответы:

106

Вам не нужен 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];
}

Легко использовать...

sortUnorderedList("ID_OF_LIST");

Live Demo →

Джош Стодола
источник
30
Одна проблема, с которой я столкнулся при таком подходе, заключается в том, что, поскольку перемещается только текст, если вы связываете данные с узлами DOM, используя jQuery.data до сортировки, эти ассоциации теперь указывают на неправильные узлы после сортировки.
Рудизм
13
Перемещение элементов с помощью innerHTML является плохим решением, поскольку они не совпадают после сортировки. Все существующие ссылки на элементы теряются. Все слушатели событий, связанные с JavaScript, теряются. Было бы лучше хранить элементы вместо innerHTML, использовать функцию сортировки (vals.sort (function (a, b) {return b.innerHTML <a.innerHTML;})) и appendChild для перемещения элементов.
Грегерс
4
Buhuuu innerHTML! Не используйте это. Это проприетарный материал Microsoft, который не был признан W3C.
Стив К
14
ИМХО это ужасный ответ. Совершенно возможно переставить узлы DOM без их сериализации и повторной десериализации, а также без уничтожения каких-либо прикрепленных свойств и / или событий.
Альнитак
4
... но если бы вы использовали jQuery, как бы вы это сделали?
Мэтью
332

Что-то вроде этого:

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

С этой страницы: http://www.onemoretake.com/2009/02/25/sorting-elements-with-jquery/

Приведенный выше код отсортирует ваш неупорядоченный список с идентификатором 'myUL'.

ИЛИ вы можете использовать плагин, как TinySort. https://github.com/Sjeiti/TinySort

SolutionYogi
источник
6
Можно ли заменить последнюю строку на $ (listitems) .appendTo (mylist); ?
Амир
26
У HL Menken есть цитата, которая описывает это решение: «Для каждой проблемы есть простое, элегантное и неправильное решение». Этот процесс выполняется за O (n ^ 2) времени. Это не заметно с относительно короткими списками, но в списке, содержащем более 100 элементов, сортировка занимает 3-4 секунды.
Натан Стронг
5
@ Натан: О «Для каждой проблемы есть простое, элегантное и неправильное решение». - Ну, неправильное решение не элегантно.
Иоганн Филипп Стратхаузен
18
Что-то может быть элегантным и интригующим, чтобы смотреть, но все же потерпеть неудачу. Элегантность не означает успеха.
Джейн Панда
13
Это решение не является неправильным. Это отвечает на вопрос. ОП не указал, что ему нужно отсортировать список из более чем 100 предметов. Если его список никогда не будет длиннее 100 пунктов, это решение вполне приемлемо. +1 за указание, что решение медленное, -1 за объявление решения, отвечающего требованиям, как «неправильного».
Самурайская душа
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;    
}

живая демонстрация: http://jsbin.com/eculis/876/edit

Джитендра Чаухан
источник
15
Это лучший ответ. Я даже как это в один сингл линии , как это: $(".list li").sort(function(a, b){return ($(b).text()) < ($(a).text());}).appendTo('.list');. Одно замечание: .text()должно быть.text().toUpperCase()
Жюль Колле
К сожалению, это решение не работает в IE, в то время как ответ PatrickHecks ниже работает во всех браузерах.
Patg
8
Остерегайтесь селектора! «.list li» выберет все потомки тегов LI, а не только непосредственные потомки.
Дуг Домени
3
@DougDomeny прав. Лучше позвонить $(".list").children(), если это возможно, или настроить селектор с непосредственными дочерними отношениями, такими как$(".list > li")
mroncetwice
1
Кстати, вот ссылка на скрипку, которую я сделал, используя этот ответ. Я настроил код как функцию «все в одном»: jsfiddle.net/mroncetwice/t0whh6fL
mroncetwice
39

Чтобы эта работа работала со всеми браузерами, включая Chrome, необходимо, чтобы функция обратного вызова sort () возвращала -1,0 или 1.

см. 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
источник
2
Не следует ли удалить все элементы li из ul.myList перед добавлением отсортированных элементов li?
Дауд
2
@ Да, элементы LI не нужно явно удалять.
Дуг Домени
1
Использование .localeCompare будет улучшением для не-ASCII символов.
Дуг Домени
1
@DougDomeny, почему не нужно явно удалять элементы li?
Bowserm
3
@bowserm, метод appendTo перемещает элементы DOM, а не копирует их.
Дуг Домени
31

Если вы используете jQuery, вы можете сделать это:

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

Обратите внимание, что возврат 1 и -1 (или 0 и 1) из функции сравнения абсолютно неверен .

Салман А
источник
7

@ SolutionYogi ответ работает как очарование, но кажется, что использование $ .each менее просто и эффективно, чем прямое добавление элементов списка:

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

скрипка

Buzut
источник
$ ('# list'). empty () -> mylist.empty () будет лучше. Не нужно снова прикасаться к DOM.
Джейкоб ван Линген
Абсолютно, я просто исправил это!
Бузут,
Это не работает в Internet Explorer (протестировано с версией 10).
Чед Джонсон
Я только что протестировал с IE11, и на самом деле он не работает. Но код SolutionYogi не работал ни под IE11 ... Это сработало для вас?
Бузут
1

улучшение, основанное на ответе Джетендры Чаухан

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

почему я считаю это улучшением:

  1. использовать eachдля поддержки работы на более чем одной ул

  2. важно использовать children('li')вместо, ('ul li')потому что мы хотим обрабатывать только прямые потомки, а не потомки

  3. использование функции со стрелкой (a,b)=>выглядит лучше (IE не поддерживается)

  4. использование ванили innerTextвместо $(a).text()повышения скорости

  5. использование ванили localeCompareулучшает скорость в случае равных элементов (редко в реальной жизни)

  6. использование appendTo(this)вместо использования другого селектора гарантирует, что даже если селектор ловит более одного уль, все равно ничего не сломается

oriadam
источник
0

Я искал сделать это сам, и я не был удовлетворен ни одним из ответов, предоставленных просто потому, что, я полагаю, это квадратичное время, и мне нужно сделать это в списках сотен пунктов длиной.

Я закончил расширять jquery, и мое решение использует jquery, но его можно легко изменить, чтобы использовать прямой javascript.

Я только получаю доступ к каждому элементу дважды и выполняю одну линейную сортировку, так что, я думаю, это должно работать намного быстрее на больших наборах данных, хотя я свободно признаюсь, что могу ошибаться там:

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)));
    }
}
Quirkles
источник
0

Поместите список в массив, используйте JavaScript .sort(), который по умолчанию является алфавитным, затем преобразуйте массив обратно в список.

http://www.w3schools.com/jsref/jsref_sort.asp

Элон Зито
источник
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 https://jsfiddle.net/97oo61nw/

Здесь мы помещаем все значения liэлементов внутри ulс определенным id(который мы предоставили в качестве аргумента функции) в массив arrи сортируем его, используя метод sort (), который по умолчанию сортируется по алфавиту. После arrсортировки массива мы зацикливаем этот массив с помощью метода forEach () и просто заменяем текстовое содержимое всех liэлементов отсортированным содержимым

Михаил
источник