按值对 JSON 进行排序

Posted

技术标签:

【中文标题】按值对 JSON 进行排序【英文标题】:Sorting JSON by values 【发布时间】:2010-10-27 06:15:09 【问题描述】:

我有一个非常简单的 JSON 对象,如下所示:


   "people":[
      
         "f_name":"john",
         "l_name":"doe",
         "sequence":"0",
         "title":"president",
         "url":"google.com",
         "color":"333333"
      ,
      
         "f_name":"michael",
         "l_name":"goodyear",
         "sequence":"0",
         "title":"general manager",
         "url":"google.com",
         "color":"333333"
      
   ]

现在这是从我的服务器端代码返回的,我运行 jQuery.each 以形成必要的 html 并输出结果。

现在我正在做的是向包含我的排序信息的服务器发送 AJAX 调用......例如“标题 DESC”并重新运行 SQL 查询以返回新的结果集。但我想避免这种情况,并使用 jQuery 对生成的 JSON 进行排序,以防止往返服务器和多个数据库访问。

如何使用 jQuery 实现这一点?

【问题讨论】:

你可能想试试这个的变体:wrichards.com/blog/2009/02/jquery-sorting-elements 仅供参考...您可以使用 Internet 上有关 javascript 数组排序的任何教程,它会直接应用于您的场景,因为 JSON 只是一个 javascript 对象/数组。 JS 没有区分对象和数组,因为无论如何在 JS 中一切基本上都是对象。 :-) @Emin,请考虑更改接受的答案,因为我提供的答案现在收到的赞成票几乎是之前接受的答案的两倍。 @SeantheBean true.. 做到了.. Sort array of objects by string property value in JavaScript的可能重复 【参考方案1】:

jQuery 对排序不是特别有帮助,但这是一个优雅而高效的解决方案。只需编写一个普通的 JS 函数,它接受属性名称和顺序(升序或降序)并使用简单的比较函数调用本机 sort() 方法:

var people = [
    
        "f_name": "john",
        "l_name": "doe",
        "sequence": "0",
        "title" : "president",
        "url" : "google.com",
        "color" : "333333",
    
    // etc
];

function sortResults(prop, asc) 
    people.sort(function(a, b) 
        if (asc) 
            return (a[prop] > b[prop]) ? 1 : ((a[prop] < b[prop]) ? -1 : 0);
         else 
            return (b[prop] > a[prop]) ? 1 : ((b[prop] < a[prop]) ? -1 : 0);
        
    );
    renderResults();

然后:

sortResults('l_name', true);

使用一个工作示例here。

【讨论】:

当我再输入几行数据时,这似乎对我不起作用。每次我尝试时,它的排序似乎都不同。这是小提琴:jsfiddle.net/Jsar8 任何帮助表示赞赏。 令人惊讶的是,Chrome(以及其他一些主要浏览器)不使用“稳定”(即一致?)排序算法。以下问题对浏览器的排序方法有一些很好的讨论:***.com/questions/1427608/…***.com/questions/234683/…***.com/questions/3026281/… 重要限制:核心排序功能在 FF 上工作,在 Chrome 24 上失败,在 android 默认浏览器上失败。 jsfiddle.net/VAKrE/377 这个函数本来就很优雅! @Hugolpz 准确地说,Chrome、Opera ***.com/questions/3026281 和我在互联网上能找到的最佳信息)。 FF 3+​​、Opera 10+、IE、Safari中使用的算法是稳定的。我之前评论中的相关 SO 问题更深入地介绍了 Array.sort() 实现。 @eaj 你指出 ECMAScript 标准是正确的——这是我的疏忽——我会相应地更新代码。但是,结果实际上是相同的,正如您在此处看到的那样:jsfiddle.net/Jsar8/1(基于 Jeff Borden 的问题示例)。只要有可能,请提供一个可行的例子来说明您的建议。【参考方案2】:

演示:https://jsfiddle.net/kvxazhso/

成功传递相等的值(保持相同的顺序)。灵活:处理升序(123)或降序(321),适用于数字、字母和 unicode。适用于所有经过测试的设备(Chrome、Android 默认浏览器、FF)。

给定数据

var people = [ 
 'myKey': 'A', 'status': 0 ,
 'myKey': 'B', 'status': 3 ,
 'myKey': 'C', 'status': 3 ,
 'myKey': 'D', 'status': 2 ,
 'myKey': 'E', 'status': 7 ,
...
];

升序或倒序排序

function sortJSON(arr, key, way) 
    return arr.sort(function(a, b) 
        var x = a[key]; var y = b[key];
        if (way === '123')  return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 
        if (way === '321')  return ((x > y) ? -1 : ((x < y) ? 1 : 0)); 
    );


people2 = sortJSON(people,'status', '321'); // 123 or 321
alert("2. After processing (0 to x if 123; x to 0 if 321): "+JSON.stringify(people2));

【讨论】:

【参考方案3】:
jQuery.fn.sort = function()   
    return this.pushStack( [].sort.apply( this, arguments ), []);  
;  

 function sortLastName(a,b)  
     if (a.l_name == b.l_name)
       return 0;
     
     return a.l_name> b.l_name ? 1 : -1;  
 ;  
  function sortLastNameDesc(a,b)  
     return sortLastName(a,b) * -1;  
 ;
var people= [

"f_name": "john",
"l_name": "doe",
"sequence": "0",
"title" : "president",
"url" : "google.com",
"color" : "333333",
,

"f_name": "michael",
"l_name": "goodyear",
"sequence": "0",
"title" : "general manager",
"url" : "google.com",
"color" : "333333",
]

sorted=$(people).sort(sortLastNameDesc);  

【讨论】:

查看我对 Bill Richards 代码的改编。它根据姓氏按降序对 json 数组进行排序。排序回调可以通过在函数的构造函数中传递字段名称来概括。 你必须在 sortLastName 中用 l_name 替换 innerHTML 澄清一下,我的第一条评论,我的意思是这段代码可以进一步修改以支持通用排序。 如果 a.l_name 和 b.l_name 相等,sortLastName() 不应该返回 0 吗?可能是因为数据的原因,这种情况下是没有必要的,但是看了代码,我不禁想到了这个:blogs.msdn.com/oldnewthing/archive/2009/05/08/9595334.aspx ... “首先,你的第一个比较函数明显违反了做比较的要求功能:如果两个项目比较相等,它必须返回零。” 是的,你是对的。当两者相等时,它应该返回 0。正如我所说,这是对其他地方的代码的快速改编。目的只是为了展示这个概念,所以我看的不够仔细。【参考方案4】:

如果您不介意使用外部库,Lodash 有很多很棒的实用程序

var people = [
  
     "f_name":"john",
     "l_name":"doe",
     "sequence":"0",
     "title":"president",
     "url":"google.com",
     "color":"333333"
  ,
  
     "f_name":"michael",
     "l_name":"goodyear",
     "sequence":"0",
     "title":"general manager",
     "url":"google.com",
     "color":"333333"
  
];


var sorted = _.sortBy(people, "l_name")

您还可以按多个属性进行排序。 Here's 一个在行动中展示它的笨蛋

【讨论】:

【参考方案5】:

解决方案适用于不同类型和大小写。例如,如果没有 toLowerCase 语句,“Goodyear”将按升序排列在“doe”之前。运行我答案底部的代码 sn-p 以查看不同的行为。

JSON 数据:

var people = [

    "f_name" : "john",
    "l_name" : "doe", // lower case
    "sequence": 0 // int
,

    "f_name" : "michael",
    "l_name" : "Goodyear", // upper case
    "sequence" : 1 // int
];

JSON 排序函数:

function sortJson(element, prop, propType, asc) 
  switch (propType) 
    case "int":
      element = element.sort(function (a, b) 
        if (asc) 
          return (parseInt(a[prop]) > parseInt(b[prop])) ? 1 : ((parseInt(a[prop]) < parseInt(b[prop])) ? -1 : 0);
         else 
          return (parseInt(b[prop]) > parseInt(a[prop])) ? 1 : ((parseInt(b[prop]) < parseInt(a[prop])) ? -1 : 0);
        
      );
      break;
    default:
      element = element.sort(function (a, b) 
        if (asc) 
          return (a[prop].toLowerCase() > b[prop].toLowerCase()) ? 1 : ((a[prop].toLowerCase() < b[prop].toLowerCase()) ? -1 : 0);
         else 
          return (b[prop].toLowerCase() > a[prop].toLowerCase()) ? 1 : ((b[prop].toLowerCase() < a[prop].toLowerCase()) ? -1 : 0);
        
      );
  

用法:

sortJson(people , "l_name", "string", true);
sortJson(people , "sequence", "int", true);

var people = [
  "f_name": "john",
  "l_name": "doe",
  "sequence": 0
, 
  "f_name": "michael",
  "l_name": "Goodyear",
  "sequence": 1
, 
  "f_name": "bill",
  "l_name": "Johnson",
  "sequence": 4
, 
  "f_name": "will",
  "l_name": "malone",
  "sequence": 2
, 
  "f_name": "tim",
  "l_name": "Allen",
  "sequence": 3
];

function sortJsonLcase(element, prop, asc) 
  element = element.sort(function(a, b) 
    if (asc) 
      return (a[prop] > b[prop]) ? 1 : ((a[prop] < b[prop]) ? -1 : 0);
     else 
      return (b[prop] > a[prop]) ? 1 : ((b[prop] < a[prop]) ? -1 : 0);
    
  );


function sortJson(element, prop, propType, asc) 
  switch (propType) 
    case "int":
      element = element.sort(function(a, b) 
        if (asc) 
          return (parseInt(a[prop]) > parseInt(b[prop])) ? 1 : ((parseInt(a[prop]) < parseInt(b[prop])) ? -1 : 0);
         else 
          return (parseInt(b[prop]) > parseInt(a[prop])) ? 1 : ((parseInt(b[prop]) < parseInt(a[prop])) ? -1 : 0);
        
      );
      break;
    default:
      element = element.sort(function(a, b) 
        if (asc) 
          return (a[prop].toLowerCase() > b[prop].toLowerCase()) ? 1 : ((a[prop].toLowerCase() < b[prop].toLowerCase()) ? -1 : 0);
         else 
          return (b[prop].toLowerCase() > a[prop].toLowerCase()) ? 1 : ((b[prop].toLowerCase() < a[prop].toLowerCase()) ? -1 : 0);
        
      );
  


function sortJsonString() 
  sortJson(people, 'l_name', 'string', $("#chkAscString").prop("checked"));
  display();


function sortJsonInt() 
  sortJson(people, 'sequence', 'int', $("#chkAscInt").prop("checked"));
  display();


function sortJsonUL() 
  sortJsonLcase(people, 'l_name', $('#chkAsc').prop('checked'));
  display();


function display() 
  $("#data").empty();
  $(people).each(function() 
    $("#data").append("<div class='people'>" + this.l_name + "</div><div class='people'>" + this.f_name + "</div><div class='people'>" + this.sequence + "</div><br />");
  );
body 
  font-family: Arial;

.people 
  display: inline-block;
  width: 100px;
  border: 1px dotted black;
  padding: 5px;
  margin: 5px;

.buttons 
  border: 1px solid black;
  padding: 5px;
  margin: 5px;
  float: left;
  width: 20%;

ul 
  margin: 5px 0px;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="buttons" style="background-color: rgba(240, 255, 189, 1);">
  Sort the JSON array <strong style="color: red;">with</strong> toLowerCase:
  <ul>
    <li>Type: string</li>
    <li>Property: lastname</li>
  </ul>
  <button onclick="sortJsonString(); return false;">Sort JSON</button>
  Asc Sort
  <input id="chkAscString" type="checkbox" checked="checked" />
</div>
<div class="buttons" style="background-color: rgba(255, 214, 215, 1);">
  Sort the JSON array <strong style="color: red;">without</strong> toLowerCase:
  <ul>
    <li>Type: string</li>
    <li>Property: lastname</li>
  </ul>
  <button onclick="sortJsonUL(); return false;">Sort JSON</button>
  Asc Sort
  <input id="chkAsc" type="checkbox" checked="checked" />
</div>
<div class="buttons" style="background-color: rgba(240, 255, 189, 1);">
  Sort the JSON array:
  <ul>
    <li>Type: int</li>
    <li>Property: sequence</li>
  </ul>
  <button onclick="sortJsonInt(); return false;">Sort JSON</button>
  Asc Sort
  <input id="chkAscInt" type="checkbox" checked="checked" />
</div>
<br />
<br />
<div id="data" style="float: left; border: 1px solid black; width: 60%; margin: 5px;">Data</div>

【讨论】:

【参考方案6】:

这是一个多级排序方法。我包含来自 Angular JS 模块的 sn-p,但是您可以通过限定排序键对象的范围来完成相同的事情,以便您的排序函数可以访问它们。你可以在Plunker看到完整的模块。

$scope.sortMyData = function (a, b)

  var retVal = 0, key;
  for (var i = 0; i < $scope.sortKeys.length; i++)
  
    if (retVal !== 0)
    
      break;
    
    else
    
      key = $scope.sortKeys[i];
      if ('asc' === key.direction)
      
        retVal = (a[key.field] < b[key.field]) ? -1 : (a[key.field] > b[key.field]) ? 1 : 0;
      
      else
      
        retVal = (a[key.field] < b[key.field]) ? 1 : (a[key.field] > b[key.field]) ? -1 : 0;
      
    
  
  return retVal;
;

【讨论】:

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

按值对 JSON 进行排序

node.js - 按值对 JSON 对象进行排序 [重复]

如何按值对 STL 映射进行排序?

在Python中按值对嵌套字典进行排序,并按另一个值对余数进行排序

按值对HashMap进行排序[重复]

如何在 JavaScript 中按值对地图进行排序?