Javascript为对象的子键排序对象数组

时间:2017-02-13 23:53:16

标签: javascript arrays sorting

我有一个对象数组,我需要在javascript(es6很好)或jquery中排序。数据比常规对象数组稍微复杂一些,因为该值位于子对象中。我需要对动态键进行排序,其中要排序的数据位于动态键的对象中。例如,我需要按“id”升序或降序排序,数据位于id.data。

    [{
    "_row": {},
    "_parent": {},
    "id": {"data": 112, "cell": {}},
    "name": {"data": "D'Amore, Volkman and Cole", "cell": {}},
    "check_name": {"data": "", "cell": {}},
    "account_number": {"data": "5534867831801846", "cell": {}},
    "main_email": {"data": "akovacek@yahoo.com", "cell": {}},
    "cc_email": {"data": "cupton@gmail.com", "cell": {}},
    "main_phone": {"data": "1-845-550-6422", "cell": {}},
    "work_phone": {"data": "+1 (859) 399-6372", "cell": {}},
    "mobile": {"data": "292-242-7626 x798", "cell": {}},
    "fax": {"data": "", "cell": {}},
    "active": {"data": 1, "cell": {}},
    "billing_address": {"data": "24226 Mackenzie Junctions Suite 393\nDonaldside, GA 87531", "cell": {}},
    "shipping_address": {"data": "478 Toy Loaf Suite 552\nWaelchiberg, ND 70701-3633", "cell": {}},
    "comments": {"data": "", "cell": {}}
}, {
    "_row": {},
    "_parent": {},
    "id": {"data": 120, "cell": {}},
    "name": {"data": "Carroll, Rice and Reilly", "cell": {}},
    "check_name": {"data": "", "cell": {}},
    "account_number": {"data": "4539358256447", "cell": {}},
    "main_email": {"data": "ocie.ebert@bergstrom.net", "cell": {}},
    "cc_email": {"data": "bmoen@kshlerin.info", "cell": {}},
    "main_phone": {"data": "612-864-9512", "cell": {}},
    "work_phone": {"data": "(519) 761-1805", "cell": {}},
    "mobile": {"data": "+1-730-669-4339", "cell": {}},
    "fax": {"data": "", "cell": {}},
    "active": {"data": 1, "cell": {}},
    "billing_address": {"data": "848 Rashawn Causeway\nHauckberg, GA 21193", "cell": {}},
    "shipping_address": {"data": "3458 Wolff Cape Suite 336\nWolfmouth, DC 35821", "cell": {}},
    "comments": {"data": "", "cell": {}}
}, {
    "_row": {},
    "_parent": {},
    "id": {"data": 122, "cell": {}},
    "name": {"data": "Denesik and Sons", "cell": {}},
    "check_name": {"data": "", "cell": {}},
    "account_number": {"data": "6011079688853496", "cell": {}},
    "main_email": {"data": "clinton41@schiller.com", "cell": {}},
    "cc_email": {"data": "daron80@corwin.info", "cell": {}},
    "main_phone": {"data": "569-382-2580 x1764", "cell": {}},
    "work_phone": {"data": "705.782.2219", "cell": {}},
    "mobile": {"data": "936-586-1978", "cell": {}},
    "fax": {"data": "", "cell": {}},
    "active": {"data": 1, "cell": {}},
    "billing_address": {"data": "1864 Donnelly Parkway Suite 222\nPort Hailieburgh, NC 08808-0938", "cell": {}},
    "shipping_address": {"data": "28476 Jerald Valleys Apt. 537\nNorth Vancemouth, DC 16865-0793", "cell": {}},
    "comments": {"data": "", "cell": {}}
}, {
    "_row": {},
    "_parent": {},
    "id": {"data": 124, "cell": {}},
    "name": {"data": "Trantow, Botsford and Runolfsson", "cell": {}},
    "check_name": {"data": "", "cell": {}},
    "account_number": {"data": "4556163511909216", "cell": {}},
    "main_email": {"data": "jordane77@adams.com", "cell": {}},
    "cc_email": {"data": "shawn34@block.info", "cell": {}},
    "main_phone": {"data": "+16989316200", "cell": {}},
    "work_phone": {"data": "969.610.8041 x8593", "cell": {}},
    "mobile": {"data": "680.717.5368", "cell": {}},
    "fax": {"data": "", "cell": {}},
    "active": {"data": 1, "cell": {}},
    "billing_address": {"data": "96778 VonRueden Square Suite 421\nKennafort, SC 70938", "cell": {}},
    "shipping_address": {"data": "13334 Orion Green\nEast Lillieborough, ND 19714", "cell": {}},
    "comments": {"data": "", "cell": {}}
}]

复杂化的下一步是我想按id排序,然后是另一个键,比如active,然后是name等。

任何想法?我可以利用.sort吗? (看起来我没有使用单元格对象,也许我可以删除它以使我的生活更轻松。我想我多年前将其添加为一个非常重要的原因)

以下是对我所知道的更新...第一种排序正常,排序多列似乎无法正常工作。

尝试1:

        //sort_array looks like [{db_field:'asc'},etc...]
    //we need to sort row based on data for this.tdo[row][db_filed]['data']
    this.tdo.sort((a,b) => {
        sort_array.forEach(sort => {
            let keys = Object.keys(sort);
            let name = keys[0];
            if(sort[keys[0]] =='asc')
            {
                this.tdo = this.tdo.sort(this.dynamicSort(name));
            }
            else
            {
                this.tdo = this.tdo.sort(this.dynamicSort('-'+name));
            }
        })

    })

从堆栈溢出Sort array of objects by string property value in JavaScript

中取出dynamicSort
dynamicSort(property) {
    let sortOrder = 1;
    if (property[0] === "-") {
        sortOrder = -1;
        property = property.substr(1);
    }
    return function (a, b) {
        let result = (a[property].data < b[property].data) ? -1 : (a[property].data > b[property].data) ? 1 : 0;
        return result * sortOrder;
    }
}

尝试2,使用thenBy非常酷。我找到了一个如何在他们的封闭问题中堆叠排序的例子:

 let sort_stack = firstBy(function (v1, v2) { return 0 });
    sort_array.forEach(sort => {
        let keys = Object.keys(sort);
        let name = keys[0];
        if(sort[keys[0]] =='asc')
        {
            sort_stack = sort_stack.thenBy(function (v1) { return v1[name].data; });
        }
        else
        {
            sort_stack = sort_stack.thenBy(function (v1) { return v1[name].data ; },-1);
        }
    })

    this.tdo.sort(sort_stack);

此外,我可能需要根据数据类型限制用户输入子排序......因为像id这样的列只会排序一次

不确定为什么我投票,这种情况非常复杂,超出了.sort文档的范围

2 个答案:

答案 0 :(得分:0)

您可以使用自定义比较功能在阵列上使用链式排序()。例如,如果数组名为“items”,则可以使用以下基本代码:

function compare(value1, value2){
  if(value1 < value2) return -1;
  else if(value1 == value2) return 0;
  else return 1;
}

items = items.sort(function(item1, item2){ // First sorting criteria, e.g. by id.data
  return compare(item1.id.data, item2.id.data);
}).sort(function(item1, item2){ // Second sorting criteria, e.g. by active.data
  return compare(item1.active.data, item2.active.data);
}).sort(function(item1, item2){  // Third sorting criteria, e.g. by name.data
  return compare(item1.name.data, item2.name.data);
});

更新的答案:

好吧,好像我误解了你,我的坏人。我现在看到你想要按照一个字段对项目进行排序,然后按照单独的列对这些排序的项目进行排序,但保留以前的排序,以类似数据库的方式。

要执行此操作,您需要将已排序的项目分组为子数组,然后按照第二个条件对它们进行单独排序。我为你创造了一个小提琴:

https://jsfiddle.net/d8vzn9b0/1/

以下是用于实现此目的的主要代码:

function compare(value1, value2){
  if(value1 < value2) return -1;
  else if(value1 == value2) return 0;
  else return 1;
}

function splitItemsByFieldValue(items, field){
  var splittedByValue = {};
  var key;

  // Group items in an object-based hash indexed by the field value
  for(var item of items){
    // We use a string prefix to make all object keys strings to prevent the "empty slots" in Javascript object or array based hashes
    key = 'value_' + item[field].data;
        if(!splittedByValue[key]) splittedByValue[key] = [];
    splittedByValue[key].push(item);
  }

  // Convert the indexed array (grouped items) to a flat array (not associative) of the grouped items as subarrays
  var splittedFlat = [], subarray;

  for(key in splittedByValue){
    subarray = splittedByValue[key];
    splittedFlat.push(subarray);
  }

  return splittedFlat;
}

var sortedItems = [];

var sortedByActive = items.sort(function(item1, item2){ // First sorting criteria, e.g. by active.data
  return compare(item1.active.data, item2.active.data);
});

for(var subarray of splitItemsByFieldValue(sortedByActive, 'active')){
  var sortedSubArray = subarray.sort(function(item1, item2){  // Second sorting criteria, e.g. by name.data
    return (item1.name && (typeof item1.name.data) == 'string') ? item1.name.data.localeCompare(item2.name.data) : 1;
  });

  for(var item of sortedSubArray){
    sortedItems.push(item);
  }
}

请注意,我创建了一个splitItemsByFieldValue()函数,允许您将已排序的项目拆分为特定字段的子数组。您可以使用此代码作为在顶部添加更多排序条件的基础。另外,请注意我使用localeCompare()按名称进行排序,因此使用自然排序(对于文本而不是数字)比较,而标准数字比较用于其他字段,如活动。

顺便说一句,没有必要按“ID”排序,因为ID总是(应该)是唯一的。您不能同时拥有2个可以具有无限量离散值的排序标准,否则将应用的唯一标准是第一个,其他标准将被忽略。例如,如果您首先按ID排序,则无需按活动排序,然后按字段排序,因为结果仍将按ID排序。

当您使用排序时,您应首先按具有有限离散值列表的列进行排序,然后您可以按可能具有连续值(例如价格,数量等)或不确定离散值的列进行排序(例如,唯一的ID)。

答案 1 :(得分:0)

var arr = [{"_row":{},"_parent":{},"id":{"data":112,"cell":{}},"rest": "abcd"},{"_row":{},"_parent":{},"id":{"data":120,"cell":{}},"rest": "rthu"},{"_row":{},"_parent":{},"id":{"data":122,"cell":{}},"rest": "just an example"},{"_row":{},"_parent":{},"id":{"data":124,"cell":{}},"rest": "efgh"}];

arr.sort((a, b) => a.id.data - b.id.data || a.rest.localCompare(b.rest) /* || another comparison ...*/); // switch a and b to swith the order

console.log(arr);