【问题标题】:Can i sort nested array using nested sort()?我可以使用嵌套排序()对嵌套数组进行排序吗?
【发布时间】:2016-07-24 12:46:42
【问题描述】:

这应该是输入数组

var a = [2,1,3,4,1,[4,6,2,4],2,4,1];

对于输出,我有两种情况:-(内部数组的索引不变)

a = [1,1,2,3,4,[2,4,4,6],1,2,4]

a = [1,1,1,2,2,[2,4,4,6],3,4,4]

这就是我想要使用的:-

a.sort(function(a,b){
  if(b instanceof Array){
    b.sort();
  }
})

【问题讨论】:

  • 数组本身应该如何排序?

标签: javascript arrays loops sorting


【解决方案1】:

Array.sort() 不是为处理部分数组而构建的,这是您在情况下需要的,但我们可以通过预处理数据(用附加信息包装它)来解决这个问题,然后排序并在结束,提取原始值:

案例1:对数组之间的部分进行排序
[2,1,3,4,1,[4,6,2,4],2,4,1] -> [1,1,2,3,4,[2,4,4,6],1,2,4]

function sort1(arr){
    //I add an artificial "property" of to the values, to "describe" the groups, and to be able to sort by
    //each Array is it's own group (so they stay in order), and the values in between share the same group
    var group = 0, 
        isArray = false;

    //an intermediate Array holding all the information (in order) to either apply it to the current Array, or to return (map) it as a new Array
    var intermediate = arr.map(function(v,i){
        //last value was an Array, this is the first value after an Array, start a new group
        if(isArray) ++group;    

        if(isArray = Array.isArray(v)){ //update isArray
            v = sort1(v);               //recursive sorting
            ++group;                    //the last group just ended here
        }

        //return a composition, that contains all the data I need to sort by
        return {
            group: group,
            value: v
        }
    }).sort(function(a, b){
        //forst sort by group, and (only) if two values share the same group, sort by the original value
        return a.group - b.group || a.value - b.value
    });

    //apply data to current Array
    intermediate.forEach(function(obj, i){ arr[i] = obj.value });
    return arr;

    //return new Array
    //return intermediate.map(function(obj){ return obj.value });
}

案例 2:将 Array 视为第一个值
[2,1,3,4,1,[4,6,2,4],2,4,1] -> [1,1,1,2,2,[2,4,4,6],3,4,4]

function sort2(arr){
    //an utility to fetch the first non-array value recursively
    function _value(v){ 
        while(Array.isArray(v)) v = v[0];
        return v;
    }

    var intermediate = arr.map(function(v, i){
        if(Array.isArray(v)) v = sort2(v);
        return {
            index: i,
            value: v,
            sortingValue: _value(v)
        }
    }).sort(function(a, b){
        return a.sortingValue - b.sortingValue || a.index - b.index;
    });

    //apply data to current Array
    intermediate.forEach(function(obj, i){ arr[i] = obj.value });
    return arr;

    //return new Array
    //return intermediate.map(function(obj){ return obj.value });
}

【讨论】:

  • 这是我想要的输出,但我仍在寻找一种更简单的方法来实现这一点。 :)
  • @AnkurMarwaha 您认为这里有什么复杂之处?预先计算值并在最后解压它们?这尽可能便宜,如果您愿意/可以将相同的代码放在排序函数中,它将被调用至少两倍的频率(对于排序数组,如果不是,则更多)
【解决方案2】:

这是完美的解决方案,使用嵌套函数调用对数组进行排序。

首先,存储所有的数组位置和子数组。

其次,将数字提取到新数组中,

最后将排序后的数组插入到与之前相同的位置。

var a = [2,1,3,4,1,[4,6,[4,5,[7,3,2,1,6],1,2],2,4],2,4,1];

function nestedSort(arr){
   var items = []; 
   var numArr = [];
    for ( key in arr){
      if (arr[key] instanceof Array)
      {
          items.push({index:key,array:arr[key]});
      }else{
          numArr.push(arr[key]);
      }
    }
   numArr.sort();
   for (key in items){
   	numArr.splice(items[key].index,0,nestedSort(items[key].array));
   }
   
  return numArr;
}

console.log(nestedSort(a));
[
  1,
  1,
  1,
  2,
  2,
  [
    2,
    4,
    [
      1,
      2,
      [
        1,
        2,
        3,
        6,
        7
      ],
      4,
      5
    ],
    4,
    6
  ],
  3,
  4,
  4
]

希望这可以解决您的问题。 :)

【讨论】:

    【解决方案3】:

    您可以遍历数组并删除所有子数组并保存它们的索引,然后对新数组进行排序并再次将排序后的子数组推送到特定索引上。

    示例

    var arr = [2, 1, 3, 4, 1, [4, 6, 2, 4], 2, 4, 1];
    var arr1 = [2, 1, 3, 4, 1, [4, 6, 2, 4], 2, 6, 4, [4, 5, 3], 1, 2, 1, 3]
    var a = [2,1,3,4,1,[4,6,[4,5,[7,3,2,1,6],1,2],2,4],2,4,1];
    
    function mySort(arr) {
      var _list = [];
      arr.forEach(function(item, index) {
        if (Array.isArray(item)) {
          _list.push({
            index: index,
            value: arr.splice(index, 1).pop()
          });
        }
      });
    
      arr.sort();
    
      _list.forEach(function(item) {
        arr.splice(item.index, 0, mySort(item.value))
      })
      return arr;
    }
    
    console.log(mySort(arr.slice()))
    console.log(mySort(arr1.slice()))
    console.log(mySort(a.slice()))

    编辑 1

    joey-etamity 的回答启发,使其适用于嵌套结构。

    【讨论】:

    • @Downvoter,我已经更新了我的答案。请检查,如果仍然缺少某些内容,请发表评论。谢谢
    • @mortezaT 你能再具体一点吗?如输出错误,或者我的代码不正确
    • 您的答案将数组前后的值排序在一起。
    • @mortezaT 不确定您在说什么,但已经更新了我的答案。检查这是否解决。
    【解决方案4】:

    不,您没有将sort 调用放在比较函数中。您将递归遍历您的数组,从下到上,并将它们一个接一个地排序。在您的情况下,如果它只是另一个数组中的一个数组,您甚至可能不需要递归:

    a.forEach(function(element) {
       if (Array.isArray(element))
           element.sort(function compare(a, b) { return a-b; });
    })
    

    (我在这里选择了一个简单的数字compare)。

    然后你会对外部数组进行排序:

    a.sort(function compare(a, b) {
        if (Array.isArray(a)) a = a[0];
        if (Array.isArray(b)) b = b[0];
        return a - b;
    })
    

    (这里compare 将数组的第一个元素与其他数字进行比较)。

    【讨论】:

      【解决方案5】:

      如果有元素一个数组,我建议拼接数组。然后对数组进行排序,重新组合数组。

      这个proposal从后面迭代,在拼接的时候保持数组完整。

      function sort(array) {
          var i = array.length,
              inside = [];
      
          while (i--) {
              if (Array.isArray(array[i])) {
                  inside.unshift({ pos: i, value: sort(array.splice(i, 1)[0]) });
              }
          }
          array.sort(function (a, b) { return a - b; });
          inside.forEach(function (a) {
              array.splice(a.pos, 0, a.value);
          });
          return array;
      }
      var a = [2, 1, 3, 4, 1, [4, 6, 2, 4], 2, 4, 1];
      
      console.log(sort(a));

      【讨论】:

        【解决方案6】:

        我认为这样使用Array.prototype.sort会更好:

        // var arr = [2, 1, 3, 4, 1, [4, 6, 2, 4], 2, 4, 1];
        var arr = [2, 1, 3, 4, 1, [4, 6, 2, 4], 2, 6, 4, [4, 5, 3], 1, 2, 1, 3];
        var chunks = chunkate(arr)
        console.log(JSON.stringify(chunks));
        
        chunks.forEach(ch => ch.sort(_sort));
        
        var result = chunks.reduce((p, c) => p.concat(c));
        console.log(JSON.stringify(result));
        
        function _sort(a, b) {
          var isAa = Array.isArray(a),
            isAb = Array.isArray(b);
          isAb && b.sort(_sort);
        
          return (isAa || isAb) ? 0 : a - b;
        }
        
        function chunkate(arr) {
          return arr.reduce((a, c) => {
            Array.isArray(c) ? a.push(chunkate(c), []) : a[a.length - 1].push(c)
            return a;
          }, [[]]);
        }

        它是如何工作的?

        如果要比较的项目是数组,那么它们不应该被替换,所以通过发送false 排序函数来识别不需要替换。否则,简单的比较就是答案。

        编辑

        正如 cmets 中所讨论的,最好将值分隔为块,然后对每个部分进行排序,然后再次连接部分。如果嵌套深度只有一层,您可以使用默认排序(不带_sort 函数),但请注意用于嵌套数组的数组中的数组。所以排序应该这样改变:

        chunks.forEach(ch => Array.isArray(ch[0])? ch[0].sort(): ch.sort());
        

        【讨论】:

        • arr = [2, 1, 3, 4, 1, [4, 6, 2, 4], 2, 6, 4,[4,5,3], 1,2,1 ,3]; -- 这给出了错误的输出 -- [1,1,1,1,2,2,2,3,[2,4,4,6],[3,4,5],3,4,4 ,6]
        • 这个解决方案是否对底层排序算法做出了一些假设?返回false不等于返回0吗?
        • 能否请您尝试使用上述评论中的输入数组?
        • sort 函数的返回值应该是数字,而不是布尔值。返回false 没有意义,确实被解释为0,所以只需返回0 而不是false
        • 从比较函数返回 false 几乎没有意义,is actually wrong here
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-25
        • 1970-01-01
        • 2019-05-14
        • 1970-01-01
        相关资源
        最近更新 更多