Сортировка списка по модулю в алфавитном порядке

У меня нет проблем с получением списка элементов и их сортировкой по алфавиту, но мне трудно понять, как это сделать с модулем.

### ОБНОВЛЕНИЕ ###

Вот код, работающий «по-моему», однако мне больше нравится возможность повторного использования ответа, представленного ниже, поэтому я принял этот ответ.

<script type="text/javascript">
$(document).ready( function() {
    $('.sectionList2').each( function() {
        var oldList = $('li a', this),
            columns = 4,
            newList = [];
        for( var start = 0; start < columns; start++){
            for( var i = start; i < oldList.length; i += columns){
                newList.push('<li><a href="' + oldList[i].href + '">' + $(oldList[i]).text() + '</a></li>');
            }
        }
        $(this).html(newList.join(''));
    });
});
</script>

Например. Скажем, у меня есть следующий неупорядоченный список:

<ul>
    <li><a href="~">Boots</a></li>
    <li><a href="~">Eyewear</a></li>
    <li><a href="~">Gloves</a></li>
    <li><a href="~">Heated Gear</a></li>
    <li><a href="~">Helmet Accessories</a></li>
    <li><a href="~">Helmets</a></li>
    <li><a href="~">Jackets</a></li>
    <li><a href="~">Mechanic's Wear</a></li>
    <li><a href="~">Pants</a></li>
    <li><a href="~">Protection</a></li>
    <li><a href="~">Rainwear</a></li>
    <li><a href="~">Random Apparel</a></li>
    <li><a href="~">Riding Suits</a></li>
    <li><a href="~">Riding Underwear</a></li>
    <li><a href="~">Socks</a></li>
    <li><a href="~">Vests</a></li>
</ul>

У меня есть этот список, отображаемый в 4 столбцах, каждый из которых расположен справа. Визуально это затрудняет поиск элементов в больших списках. Выход, который мне нужен, таков:

<ul>
    <li><a href="~">Boots</a></li>
    <li><a href="~">Helmet Accessories</a></li>
    <li><a href="~">Pants</a></li>
    <li><a href="~">Riding Suits</a></li>
    <li><a href="~">Eyewear</a></li>
    <li><a href="~">Helmets</a></li>
    <li><a href="~">Protection</a></li>
    <li><a href="~">Riding Underwear</a></li>
    <li><a href="~">Gloves</a></li>
    <li><a href="~">Jackets</a></li>
    <li><a href="~">Rainwear</a></li>
    <li><a href="~">Socks</a></li>
    <li><a href="~">Heated Gear</a></li>
    <li><a href="~">Mechanic's Wear</a></li>
    <li><a href="~">Random Apparel</a></li>
    <li><a href="~">Vests</a></li>
</ul>

То, что я ищу, - это функция, с помощью которой я могу передать свой массив элементов списка и вернуть мой массив, отсортированный по алфавиту, с выбранным модулем; в данном случае 4.

Любая помощь будет оценена по достоинству, поскольку я не могу найти документацию по этому вопросу.


person S16    schedule 10.09.2010    source источник
comment
Не могли бы вы опубликовать код, который у вас уже есть?   -  person Cristian Sanchez    schedule 10.09.2010
comment
И, если вы разрабатываете это из бэкэнда, почему вы не делаете этого на стороне сервера?   -  person Chubas    schedule 10.09.2010
comment
На самом деле для этого есть CSS-решение с column-count   -  person Yi Jiang    schedule 10.09.2010
comment
Бэкенд-решение было бы идеальным, но в данном случае невозможно. То, что у меня есть до сих пор, взрывается, и это не лучшее место для начала.   -  person S16    schedule 10.09.2010


Ответы (4)


  1. Расставьте список по алфавиту. Это уже сделано в вашем случае, но если нет:

    function alphabetizeElements(a, b)
    {
        var aText = $(a).text();
        var bText = $(b).text();
        return aText > bText ? 1 : aText < bText ? -1 : 0;
    }
    var alphabetizedList = $("#myList li").sort(alphabetizeElements);
    
  2. Сохраните алфавитный индекс каждого элемента:

    $.each(alphabetizedList, function(i)
    {
        $(this).data("alphaIndex", i);
    });
    
  3. Сначала отсортируйте алфавитный список по модулю, а затем индексируйте:

    function listColumnSortFn(columns)
    {
        return function(a, b)
        {
            var aIndex = $(a).data("alphaIndex");
            var bIndex = $(b).data("alphaIndex");
            return ((aIndex % columns) - (bIndex % columns)) || (aIndex - bIndex);
        }
    }
    var columnSortedList = alphabetizedList.sort(listColumnSortFn(4));
    
  4. Замените элементы списка отсортированными элементами:

    $("#myList li").remove();
    $("#myList").append(columnSortedList);
    

Вот и все вместе:

function sortList(columns)
{
    var alphabetizedList = $("#myList li").sort(alphabetizeElements);
    $.each(alphabetizedList, function(i)
    {
        $(this).data("alphaIndex", i);
    });
    var columnSortedList = alphabetizedList.sort(listColumnSortFn(columns));
    $("#myList li").remove();
    $("#myList").append(columnSortedList);
}
function alphabetizeElements(a, b)
{
    var aText = $(a).text();
    var bText = $(b).text();
    return aText > bText ? 1 : aText < bText ? -1 : 0;
}
function listColumnSortFn(columns)
{
    return function(a, b)
    {
        var aIndex = $(a).data("alphaIndex");
        var bIndex = $(b).data("alphaIndex");
        return ((aIndex % columns) - (bIndex % columns)) || (aIndex - bIndex);
    }
}
$(function()
{
    sortList(4);
});
person gilly3    schedule 10.09.2010

var columnify = function (a,n) { 
    var result = []; 
    for (var i = 0, lastIndex = a.length - 1; i < lastIndex; i++) 
       result.push(a[i * n % (lastIndex)]); 
    result[lastIndex] = a[lastIndex];
    return result; 
}

var products = ["Boots",
"Eyewear",
"Gloves",
"Heated Gear",
"Helmet Accessories",
"Helmets",
"Jackets",
"Mechanic's Wear",
"Pants",
"Protection",
"Rainwear",
"Random Apparel",
"Riding Suits",
"Riding Underwear",
"Socks",
"Vests",]

columnify(products, 4)
["Boots", "Helmet Accessories", "Pants", "Riding Suits", "Eyewear", "Helmets", "Protection", "Riding Underwear", "Gloves", "Jackets", "Rainwear", "Socks", "Heated Gear", "Mechanic's Wear", "Random Apparel", "Vests"]

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

Кроме того, я не тестировал его ни с чем, кроме этого списка. Так что я бы сделал это, если бы я был тобой. Из того, что я вижу, это работает, только если длина списка кратна n. Не очень хорошее решение, но мне уже поздно, и я не могу придумать что-нибудь лучше.

РЕДАКТИРОВАТЬ: исправлена ​​проблема с последним элементом

person Cristian Sanchez    schedule 10.09.2010
comment
теория довольно здравая, но реализация неверна. Передача массива из 17 элементов с n = 4 дает 0 4 8 12 четыре раза с последними 16 в пятой строке. - person ErikE; 10.09.2010
comment
@Emtucidifor: Ага. Как я уже сказал, это не работает, когда n%length != 0. - person Cristian Sanchez; 10.09.2010

Посмотрите, сработает ли это: http://jsfiddle.net/6xm9m/2.

var newList = new Array();
var listItem = $('#list > li');
var mod = 4;
var colCount = Math.ceil(listItem.length / mod);

listItem.each(function(index) {
    var newIndex = ((index % colCount) * mod) + Math.floor(index / colCount);
    // $(this).text(newIndex);

    newList[newIndex] = this;
});

$('#list').empty();

for(var i = 0; i < newList.length; i++){
    $('#list').append(newList[i]);
}

Возможно, нужны улучшения, но я не совсем уверен, насколько хорошо это вообще работает.

person Yi Jiang    schedule 10.09.2010

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

function pivotArray(arr, columns) {
   var l = arr.length, out = [], ind = 0, i = 0;
   for (; i < l; i += 1) {
      out[ind] = arr[i];
      ind += columns;
      if (ind >= l) {
         ind = ind % columns + 1;
      }
   }
   return out;
}

И вот тест, чтобы доказать, что это работает (проверено в Firefox 3.6.9, IE 6, Chrome 1.0.154.36):

<html>
<head>
<style type="text/css">
a.panelnum {
   display:block;
   float:left;
   width:40px;
   height:40px;
   border:1px solid black;
   text-align:center;
   vertical-align:middle;
   text-decoration:none;
   font-size:2em;
}
</style>
</head>
<body onload="doit(17, 4);">
<div id="output" style="border:1px solid blue;">
</div>
<script type="text/javascript">

function pivotArray(arr, columns) {
   var l = arr.length, out = [], ind = 0, i = 0;
   for (; i < l; i += 1) {
      out[ind] = arr[i];
      ind += columns;
      if (ind >= l) {
         ind = ind % columns + 1;
      }
   }
   return out;
}

function doit(size, columns) {
   document.getElementById('output').innerHTML = 'starting';
   var l = size;
   var inp = [];
   for (var i = 0; i < l; i += 1) {
      inp[i] = i;   
   }
   var result = pivotArray(inp, columns);
   var str = '';
   for (i = 0; i < l; i += 1) {
      str += '<a class="panelnum">' + result[i] + '</a>';
   }
   var d = document.getElementById('output')
   d.innerHTML = '<p>Some pre text</p>' + str + '<p style="clear:both;">and some post text</p>';
   d.style.width = (columns * d.childNodes[1].offsetWidth + 2) + 'px';
}
</script>
</body>
</html>

Еще одна вещь: может быть полезно просто перемещать элементы на месте. У меня почти был сценарий для этого, но мой сценарий работал в обратном направлении (как будто поплавки сначала шли сверху вниз). Если у меня будет время, я поработаю над этим и опубликую код.

P.S. Кто-нибудь хочет подсказать, почему мне пришлось добавить 2 к расчету ширины для IE6? Подождите... это границы div, не так ли?

person ErikE    schedule 10.09.2010