如何按列值对二维数组进行排序?

Posted

技术标签:

【中文标题】如何按列值对二维数组进行排序?【英文标题】:How to sort 2 dimensional array by column value? 【发布时间】:2013-04-12 09:20:55 【问题描述】:

谁能帮我在 javascript 中对二维数组进行排序?

它将具有以下格式的数据:

[12, AAA]
[58, BBB]
[28, CCC]
[18, DDD]

排序后应该是这样的:

[12, AAA]
[18, DDD]
[28, CCC]
[58, BBB]

所以基本上,按第一列排序。

干杯

【问题讨论】:

这里有你需要知道的一切:MDN - Array.sort() 请接受@PramodVemulapalli 的回答,目前高票的都是错的! @jahroy:这与类型强制无关,而与一致性比较函数的要求有关。 【参考方案1】:

就这么简单:

var a = [[12, 'AAA'], [58, 'BBB'], [28, 'CCC'],[18, 'DDD']];

a.sort(sortFunction);

function sortFunction(a, b) 
    if (a[0] === b[0]) 
        return 0;
    
    else 
        return (a[0] < b[0]) ? -1 : 1;
    

我邀请你到read the documentation。

如果要按第二列排序,可以这样做:

a.sort(compareSecondColumn);

function compareSecondColumn(a, b) 
    if (a[1] === b[1]) 
        return 0;
    
    else 
        return (a[1] < b[1]) ? -1 : 1;
    

【讨论】:

请实际测试您的代码。 jsfiddle.net/DuR4B/2 。直接来自您发布的文档链接:“如果未提供 compareFunction,则通过将元素转换为字符串并按字典顺序(“字典”或“电话簿”,而不是数字)比较字符串来对元素进行排序。例如,“80”来了按字典顺序在“9”之前,但在数字排序中,9 在 80 之前。” @Ian - 你是对的。好点子。我想我过于兴奋地证明了一个关于简单性的观点。我确实测试过,但不完全。现在我会修复它...我希望样本数据在我把鸡蛋涂满脸之前证明了你的观点! 哈哈我知道我知道,我讨厌这种事情发生。它看起来很正确,但是内部发生了一些变化,并没有按预期进行。有点像将字符串与&lt;&gt; 进行比较。无论如何,我喜欢这个更新:) @Ash - 查看文档的最佳位置。我喜欢 Mozilla 的文档,所以当我对 JS 函数有疑问时,我总是用谷歌搜索 "mdn function_name." 在这种情况下,搜索词是 "mdn array.sort " 给你带来here. ... 正如您将在文档中看到的那样,array.sort() 方法将函数作为参数,这在 JavaScript 中相当常见。 array.sort() 方法的设计方式使其知道如何处理传递给它的函数:它使用它来比较其元素。这是really lame fiddle,我试图演示如何将函数作为引用传递……抱歉,这太糟糕了。【参考方案2】:

最好的方法是使用以下方法,因为第一列中可能存在重复值。

var arr = [[12, 'AAA'], [12, 'BBB'], [12, 'CCC'],[28, 'DDD'], [18, 'CCC'],[12, 'DDD'],[18, 'CCC'],[28, 'DDD'],[28, 'DDD'],[58, 'BBB'],[68, 'BBB'],[78, 'BBB']];

arr.sort(function(a,b) 
    return a[0]-b[0]
);

【讨论】:

这是正确答案,它考虑了数字中的两个数字。谢谢!【参考方案3】:

试试这个

//WITH FIRST COLUMN
arr = arr.sort(function(a,b) 
    return a[0] - b[0];
);


//WITH SECOND COLUMN
arr = arr.sort(function(a,b) 
    return a[1] - b[1];
);

注意:原始答案使用大于 (>) 而不是减号 (-),这就是 cmets 所指的不正确。

【讨论】:

8 票赞成一个明显错误的解决方案?我无法相信这。请阅读 comparison functions 并了解它们何时需要返回负值。 正如 Bergi 所说,这不是正确的解决方案。虽然它可能在许多情况下都有效,但有时它不会按预期工作,并且您会摸不着头脑(这发生在我身上)。问题的症结在于,这个方案中的比较函数只返回两个状态(真/1、假/0),但应该返回三个状态(零、大于零、小于零)。 对我不起作用。 @jahroy 是正确答案的人 请注意阅读 cmets 的人:答案已于 1 月 5 日更正。现在正确(比较函数返回三种可能的状态)。 @Bergi,感谢您指出这一点。 (对我来说,它在 IE11 中无法正常工作)并且在看到您的评论之前我无法理解(为什么它在 chrome 中工作)。谢谢!【参考方案4】:

使用箭头函数,并按第二个字符串字段排序

var a = [[12, 'CCC'], [58, 'AAA'], [57, 'DDD'], [28, 'CCC'],[18, 'BBB']];
a.sort((a, b) => a[1].localeCompare(b[1]));
console.log(a)

【讨论】:

【参考方案5】:

如果您和我一样,您不会希望每次更改排序所依据的列时都更改每个索引。

function sortByColumn(a, colIndex)

    a.sort(sortFunction);

    function sortFunction(a, b) 
        if (a[colIndex] === b[colIndex]) 
            return 0;
        
        else 
            return (a[colIndex] < b[colIndex]) ? -1 : 1;
        
    

    return a;


var sorted_a = sortByColumn(a, 2);

【讨论】:

我刚刚看到了你的答案,在自己用完全相同的推理起草了一个答案之后——有一点不同——我实际上返回了函数来直接排序。【参考方案6】:

一行:

var cars = [
  type:"Volvo", year:2016,
  type:"Saab", year:2001,
  type:"BMW", year:2010
]


function myFunction() 
  return cars.sort((a, b)=> a.year - b.year)

【讨论】:

【参考方案7】:

如果您想根据第一列(包含 number 值)进行排序,请尝试以下操作:

arr.sort(function(a,b)
  return a[0]-b[0]
)

如果你想根据第二列(包含 string 值)进行排序,那么试试这个:

arr.sort(function(a,b)
  return a[1].charCodeAt(0)-b[1].charCodeAt(0)
)

附:对于第二种情况,您需要比较它们的 ASCII 值。

【讨论】:

【参考方案8】:

没什么特别的,只是节省了从数组中返回某个索引处的值所需的成本。

function sortByCol(arr, colIndex)
    arr.sort(sortFunction)
    function sortFunction(a, b) 
        a = a[colIndex]
        b = b[colIndex]
        return (a === b) ? 0 : (a < b) ? -1 : 1
    

// Usage
var a = [[12, 'AAA'], [58, 'BBB'], [28, 'CCC'],[18, 'DDD']]
sortByCol(a, 0)
console.log(JSON.stringify(a))
// "[[12,"AAA"],[18,"DDD"],[28,"CCC"],[58,"BBB"]]"

【讨论】:

这个答案和我的here有什么不同? 1.您一次又一次地使用a[colIndex],但我在这里a = a[colIndex] 抓住了它。它更有效率。 2.我使用了不同风格的if,使它更短。 3. 由于sortByCol 函数,我没有返回arr,这意味着我的函数不能用于创建另一个引用。希望对您有所帮助!【参考方案9】:

站在 charles-clayton 和 @vikas-gautam 的肩膀上,我添加了字符串测试,如果列具有 OP 中的字符串,则需要该测试。

return isNaN(a-b) ? (a === b) ? 0 : (a < b) ? -1 : 1 : a-b  ;

测试isNaN(a-b) 确定字符串是否不能强制转换为数字。如果可以,那么a-b 测试是有效的。

请注意,对混合类型的列进行排序总是会产生有趣的结果,因为严格相等测试(a === b) 总是会返回 false。 See MDN here

这是带有 Logger 测试的完整脚本 - 使用 Google Apps 脚本。

function testSort()

function sortByCol(arr, colIndex)
    arr.sort(sortFunction);
    function sortFunction(a, b) 
        a = a[colIndex];
        b = b[colIndex];
       return isNaN(a-b) ? (a === b) ? 0 : (a < b) ? -1 : 1 : a-b  ;  // test if text string - ie cannot be coerced to numbers.
       // Note that sorting a column of mixed types will always give an entertaining result as the strict equality test will always return false
       // see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness

       

// Usage
var a = [ [12,'12', 'AAA'],
          [12,'11', 'AAB'],
          [58,'120', 'CCC'],
          [28,'08', 'BBB'],
          [18,'80', 'DDD'],
        ]
    var arr1 = a.map(function (i)return i;).sort();  // use map to ensure tests are not corrupted by a sort in-place.

    Logger.log("Original unsorted:\n     " + JSON.stringify(a));
    Logger.log("Vanilla sort:\n     " + JSON.stringify(arr1));
    sortByCol(a, 0);
    Logger.log("By col 0:\n     " + JSON.stringify(a));
    sortByCol(a, 1);
    Logger.log("By col 1:\n     " + JSON.stringify(a));
    sortByCol(a, 2);
    Logger.log("By col 2:\n     " + JSON.stringify(a));

/* vanilla sort returns " [
                            [12,"11","AAB"],
                            [12,"12","AAA"],
                            [18,"80","DDD"],
                            [28,"08","BBB"],
                            [58,"120","CCC"]
                          ]
   if col 0 then returns "[
                            [12,'12',"AAA"],
                            [12,'11', 'AAB'],
                            [18,'80',"DDD"],
                            [28,'08',"BBB"],
                            [58,'120',"CCC"]
                          ]"
   if col 1 then returns "[
                            [28,'08',"BBB"],
                            [12,'11', 'AAB'],
                            [12,'12',"AAA"],
                            [18,'80',"DDD"],
                            [58,'120',"CCC"],

                          ]"
   if col 2 then returns "[
                            [12,'12',"AAA"],
                            [12,'11', 'AAB'],
                            [28,'08',"BBB"],
                            [58,'120',"CCC"],
                            [18,'80',"DDD"],
                          ]"
*/


【讨论】:

可能感兴趣的更新 - 2019 年 7 月 2 日。排序现在“稳定”。在这里阅读。 (通过 Mathias BynensVerified @mathias)v8.dev/features/stable-sort【参考方案10】:

由于我的用例涉及数十列,我稍微扩展了@jahroy 的答案。 (也刚刚意识到@charles-clayton 也有同样的想法。) 我传递了我想要排序的参数,排序函数被重新定义为所需的索引以进行比较。

var ID_COLUMN=0
var URL_COLUMN=1

findings.sort(compareByColumnIndex(URL_COLUMN))

function compareByColumnIndex(index) 
  return function(a,b)
    if (a[index] === b[index]) 
        return 0;
    
    else 
        return (a[index] < b[index]) ? -1 : 1;
    
  

【讨论】:

【参考方案11】:

Sabbir Ahmed 好主意,但只按第一个字符排序,三个:

array.sort((a, b) => (a[n].charCodeAt(0)*1000000 + a[n].charCodeAt(1)*1000 + a[n].charCodeAt(2)) - (b[n].charCodeAt(0)*1000000 + b[n].charCodeAt(1)*1000 + b[n].charCodeAt(2)));

【讨论】:

以上是关于如何按列值对二维数组进行排序?的主要内容,如果未能解决你的问题,请参考以下文章

在C#中按列对二维数组进行排序

按特定键的内部数组的值对PHP二维数组进行排序[重复]

如何按列对多维数组进行排序?

java中怎么对二维数组的列排序?

基于列对二维向量数组进行排序

Python使用numpy函数hsplit水平(按列)拆分numpy数组(返回拆分后的numpy数组列表)实战:水平(按列)拆分二维numpy数组split函数水平(按列)拆分二维numpy数组