【问题标题】:How can I sort an array, yet exclude certain elements (to be kept at the same position in the array)如何对数组进行排序,但排除某些元素(保持在数组中的相同位置)
【发布时间】:2010-03-25 20:27:12
【问题描述】:

这将在 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>

谢谢!

【问题讨论】:

    标签: javascript jquery sorting arrays


    【解决方案1】:

    算法是:

    • 提取和排序未标记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);
      

    【讨论】:

    • 这是与我最终得到的代码最相似的代码,因此我将其标记为正确 - 我确信 petersendidit 提供的解决方案也很好(尽管它未经测试)。谢谢!
    【解决方案2】:

    应该这样做:

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

    这会缓存具有类停留的项目的索引,然后按分数进行排序,然后将具有类停留的项目替换回正确的位置。

    【讨论】:

      【解决方案3】:

      您认为该解决方案是通用的并且适用于任何开发环境是正确的。

      您需要将您的元素列表划分为两个不同的列表 - 一个要排序,一个留在原地。然后,对第一个列表进行排序并与第二个列表合并。

      您面临的关键问题是:如果您的比较函数依赖于任何外部状态(如 item位置)。

      【讨论】:

      • 我应该使用 jQuery 合并功能还是连接数组并使用?当索引相同时,如何确保我的“固定”项目数组优先?您提出的解决方案正是我第一次尝试这样做的方式,但我无法使其发挥作用。至少我知道我走在正确的轨道上。感谢您的意见!
      • @Konstantin 的回答对我来说似乎不错(我的 Javascript 无法胜任。+1)
      【解决方案4】:

      正如 Bevan 指出的那样,这行不通,但出于教育目的,我将把它留在这里:

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

      注意:您需要使用“糖”作为名称参数来设置糖数据:

      .data('sugar', sugarcontent[i]);
      

      【讨论】:

      • 这种方法的问题是固定的项目成为排序的障碍——任何低于固定点的项目永远不会移动到它上面,反之亦然。
      • 感谢指出语法错误,我已经修复了上面的示例代码。
      猜你喜欢
      • 1970-01-01
      • 2018-01-21
      • 2015-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多