根据数字数组的第一个和最后一个值对数组进行排序

时间:2017-12-01 23:25:54

标签: javascript arrays sorting

我有一个数组数组。

每个数字数组始终是升序序列,例如[8, 9, 10]

我想根据以下内容对每个数值数组进行排序:

  1. 数组中的第一个(也是最低的)数字。
  2. 他们的范围。
  3. 例如,给出以下内容:

    [
      [1],
      [2, 3],
      [10],
      [11, 12, 13],
      [3, 4],
      [2, 3, 4],
      [1, 2, 3, 4, 5, 6],
      [10, 11, 12],
      [7, 8, 9],
      [1, 2, 3],
      [10, 11],
    ]
    

    结果应为:

    [
      [1],
      [1, 2, 3],
      [1, 2, 3, 4, 5, 6],
      [2, 3],
      [2, 3, 4],
      [3, 4],
      [7, 8, 9],
      [10],
      [10, 11],
      [10, 11, 12],
      [11, 12, 13],
    ]
    

    结果非常接近使用:

    arr.sort((a, b) => a[0] - b[0]);
    

    但不完全。

    以下是我的示例代码:https://repl.it/repls/MadeupMediumpurpleCavy

    我有没有办法使用Array.prototype.sort实现这一目标?

3 个答案:

答案 0 :(得分:2)

您需要映射数组并对每个元素进行排序,然后对外部数组进行排序。

yourArray
  .map(arr => arr.sort()) // Sort each subarray
  .sort((a,b) => a[0]-b[0] ? a[0]-b[0] : a.length - b.length) // Sort the outer array 

我们根据每个子数组的第一个元素对外部数组进行排序,如果比较子数组的第一个元素是等于那么差值为0,在这种情况下我们回退到条件的第二部分并且我们应用排序根据长度。

这是一个稍短的版本:

yourArray
  .map(arr => arr.sort())
  .sort((a,b) => a[0]-b[0] || a.length - b.length) 

以下是演示:



var arr = [
  [1],
  [2, 3],
  [10],
  [11, 12, 13],
  [3, 4],
  [2, 3, 4],
  [1, 2, 3, 4, 5, 6],
  [10, 11, 12],
  [7, 8, 9],
  [1, 2, 3],
  [10, 11],
];

var sorted = arr.map(arr => arr.sort())
  .sort((a, b) => a[0] - b[0] || a.length - b.length);

console.log(sorted)




答案 1 :(得分:2)

目前,您的代码只通过调用sort中的compareFunction查看每个数组的第一个元素来对数组进行排序:

const actual = difficulties.sort((a, b) => a[0] - b[0])

如果第一个元素的值相等,例如:

[2, 3, 4]

[2, 3]

预期的结果是将它们保持在它们当前的相同顺序,但不是!通过一些wibbly摇摇欲坠的时间wimey ......东西...在某些情况下,如果结果语句解析为0,它们就会被切换。据我所知,这些实例是不可预测的,可能与特定浏览器有关,也可能没有。

所以此时我们在这里使用sort函数的已知结果如下:

a[0] - b[0] < 0: do nothing
a[0] - b[0] = 0: undef (maybe move maybe not)
a[0] - b[0] > 0: move element b to before element a

如上所述,如果数组(a和b)的第一个元素相同,则需要对范围进行排序。幸运的是,在您的数据集中,范围直接对应于数组的长度,因此它使事情更简单。

这是一个很好的说法,逻辑运算符不必在javascript中专门用于布尔值。也可以使用整数!使用不同于布尔值的数据类型,结果可能会略微混乱,但这在此特定示例中非常重要:

唯一的假整数是0! 所有非0整数都是真的。

SO ......

如果第一个值为真,则OR短路,这意味着如果左语句解析为非0,则OR语句返回非0整数,并且不继续评估正确的语句。

请考虑以下事项:

a[0] - b[0] || a.length - b.length

使用示例数组:

[1, 2, 3]

[2, 3]

结果值为:

a[0] = 1
b[0] = 2

a[0] - b[0] = -1

因此:

a[0] - b[0] || a.length - b.length

解析为-1 ||并不重要(1)

-1非0,因此该OR语句将-1返回到sort函数,该函数将元素保持在原来的位置。

与以下内容相反:

[2, 3, 4]

[2, 3]

结果值为:

a[0] = 2
b[0] = 2

a[0] - b[0] = 0

因此:

a[0] - b[0] || a.length - b.length

解析为0 || 1

此OR语句返回1,因为0为假,1为真。

1是一个正数,它对于排序函数意味着(如上所述)将元素b带到元素a后面。

试图尽可能详细。希望这有帮助!

答案 2 :(得分:1)

在您的情况下,只比较第一个元素和长度,就像在另一个答案中一样,效率最高:

var arr = [ [1], [2, 3], [10], [11, 12, 13], [3, 4], [2, 3, 4], 
            [1, 2, 3, 4, 5, 6], [10, 11, 12], [7, 8, 9], [1, 2, 3], [10, 11] ]

arr.sort((a, b) => a[0] - b[0] || a.length - b.length)

console.log( JSON.stringify(arr).replace(/],/g, '],\n ') )

但为了完整性,我正在添加更多通用数组比较方法以防万一:

var arr = [ [1], [2, 3], [10], [11, 12, 13], [3, 4], [2, 3, 4], 
            [1, 2, 3, 4, 5, 6], [10, 11, 12], [7, 8, 9], [1, 2, 3], [10, 11] ]

function compareArrays(a, b) { 
  for (var len = Math.min(a.length, b.length), diff, i = 0; i < len; i++)
     if (diff = a[i] - b[i]) return diff
   return a.length - b.length
}

arr.sort(compareArrays)

console.log( JSON.stringify(arr).replace(/],/g, '],\n ') )