Как я могу отсортировать массив, но исключить определенные элементы (чтобы сохранить в той же позиции в массиве) - PullRequest
6 голосов
/ 25 марта 2010

Это будет реализовано в Javascript (jQuery), но я предполагаю, что метод можно использовать на любом языке.

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

Рассматриваемый массив построен из списка <li> элементов, и я использую значения .data (), прикрепленные к элементу списка, в качестве значения, по которому нужно отсортировать.

Какой подход будет лучше здесь?

<ul id="fruit">
  <li class="stay">bananas</li>
  <li>oranges</li>
  <li>pears</li>
  <li>apples</li>
  <li class="stay">grapes</li>
  <li>pineapples</li>
</ul>

<script type="text/javascript">
    var sugarcontent = new Array('32','21','11','45','8','99');
    $('#fruit li').each(function(i,e){
       $(this).data('sugar',sugarcontent[i]);
    })
</script>

Я хочу отсортировать список со следующим результатом ...

<ul id="fruit">
      <li class="stay">bananas</li> <!-- score = 32 -->
      <li>pineapples</li> <!-- score = 99 -->
      <li>apples</li> <!-- score = 45 -->
      <li>oranges</li> <!-- score = 21 -->
      <li class="stay">grapes</li> <!-- score = 8 -->
      <li>pears</li> <!-- score = 11 -->
  </ul>

Спасибо!

Ответы [ 4 ]

7 голосов
/ 26 марта 2010

Алгоритм:

  • Извлечение и сортировка предметов, не отмеченных stay
  • Слияние stay предметов и отсортированных предметов

    var sugarcontent = new Array(32, 21, 11, 45, 8, 99);
    
    var items = $('#fruit li');
    
    items.each(function (i) {
        $(this).data('sugar', sugarcontent[i]);
        // Show sugar amount in each item text - for debugging purposes
        if ($(this).hasClass('stay'))
            $(this).text("s " + $(this).text());
        else
            $(this).text(sugarcontent[i] + " " + $(this).text());
    });
    
    // Sort sortable items
    var sorted = $(items).filter(':not(.stay)').sort(function (l, r) {
        return $(l).data('sugar') - $(r).data('sugar');
    });
    
    // Merge stay items and sorted items
    var result = [];
    var sortedIndex = 0;
    
    for (var i = 0; i < items.length; i++)
        if (!$(items[i]).hasClass('stay')) {
            result.push(sorted[sortedIndex]);
            sortedIndex++;
        }
        else
            result.push(items[i]);
    
    // Show result
    $('#fruit').append(result);
    
3 голосов
/ 26 марта 2010

Это должно сделать это:

var sugarcontent = new Array('32','21','11','45','8','99');
var list = $('#fruit');
var lis = list.find('li').each(function(i,e){
   $(this).data('score',sugarcontent[i]);
});
var stay = lis.filter('.stay').each(function(){
    $(this).data('index',$(this).index());
});
lis.sort(function(a,b){
    return $(b).data('score') - $(a).data('score');
}).appendTo(list);
stay.each(function(){
    var index = $(this).data('index');
    if (index == 0) {
        list.prepend(this);
    } else {
        lis.filter(':eq('+index+')').insertAfter(this);
    }
}

Это кэширует индекс предметов с классом пребывания, а затем выполняет сортировку по количеству очков, а затем заменяет элементы с классом остаться в правильном месте.

1 голос
/ 25 марта 2010

Вы правы, считая, что решение является универсальным и применимо к любой среде разработки.

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

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

0 голосов
/ 25 марта 2010

Это не сработает, как указал Беван, но я оставлю это здесь для образовательных целей:

$('#fruit li').sort(function(a, b) {
    return ($(a).hasClass('stay') || $(b).hasClass('stay'))
        ? 0 : (a.data('sugar') > b.data('sugar') ? 1 : -1);
}).appendTo('#fruit');

Примечание. Вам необходимо установить данные сахара с помощью параметра "sugar" в качестве аргумента имени:

.data('sugar', sugarcontent[i]);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...