简体   繁体   English

如何对对象数组和数组子集进行排序

[英]How to sort array of objects and subset of array

Schema 架构

var my_array = [ 
{
    "title": "a",
    "pinned": {
        "status": "true",
        "order": "1"
    }
},
{
    "title": "d",
    "pinned": {
        "status": "false",
        "order": "n/a"
    }
},
{
    "title": "c",
    "pinned": {
        "status": "true",
        "order": "0"
    }
},
{
    "title": "b",
    "pinned": {
        "status": "false",
        "order": "n/a"
    }
}
];

Desired Behaviour 期望的行为

Sort objects by title alphabetically, title按字母顺序对对象进行排序,
unless they have a pinned status of true , 除非它们的pinned状态为true
in which case move this "subset" of items to the beginning of the array, 在这种情况下,将此项目的“子集”移动到数组的开头,
sorted by their pinned.order value. 按其pinned.order值排序。

An example scenario would be a forum which had posts sorted by date, but also had sticky posts at the top, which were sorted by a defined order. 一个示例场景是一个论坛,该论坛的帖子按日期排序,但最上面的粘性帖子按定义的顺序排序。

The original schema would, therefore, be displayed as: 因此,原始架构将显示为:

[ 
{// i am at the top, because i have a pinned status of true and order of 0  
    "title": "c",
    "pinned": {
        "status": "true",
        "order": "0"
    }
},
{// i am second from the top, because i have a pinned status of true and order of 1  
    "title": "a",
    "pinned": {
        "status": "true",
        "order": "1"
    }
},
{// i follow in alphabetical order 
    "title": "b",
    "pinned": {
        "status": "false",
        "order": "n/a"
    }
},
{// i follow in alphabetical order 
    "title": "d",
    "pinned": {
        "status": "false",
        "order": "n/a"
    }
}
]

What I've Tried 我尝试过的

my_array.sort(function(a, b) {
    return a.pinned.order.localeCompare(b.pinned.order) || a.title.localeCompare(b.title);
});

based on this answer: 根据以下答案:

https://stackoverflow.com/a/45741804 https://stackoverflow.com/a/45741804

I also tried... 我也尝试过...

I thought about creating two separate arrays based on the value of pinned.status , sorting them separately, and then recombining them (as shown below), but I'm wondering if there is something more elegant? 我考虑过根据pinned.status的值创建两个单独的数组,分别对它们进行排序,然后重新组合(如下所示),但是我想知道是否还有更优雅的方法?

var my_array = [ 
{
    "title": "a",
    "pinned": {
        "status": "true",
        "order": "1"
    }
},
{
    "title": "d",
    "pinned": {
        "status": "false",
        "order": "n/a"
    }
},
{
    "title": "c",
    "pinned": {
        "status": "true",
        "order": "0"
    }
},
{
    "title": "b",
    "pinned": {
        "status": "false",
        "order": "n/a"
    }
}
];


var my_subset = [];

for (var i = 0; i < my_array.length; i++) {

    if (my_array[i].pinned.status === "true") {
        // add to subset
        my_subset.push(my_array[i]);
        // remove from original array
        my_array.splice(i, 1);
    }

}

// sort "pruned" original array alphabetically
my_array.sort(function(a, b) {
    return a.title.localeCompare(b.title);
});

// sort subset array by pinned.order
my_subset.sort(function(a, b) {
    return a.pinned.order.localeCompare(b.pinned.order, undefined, { numeric: true });
});

// prepend subset to original array
var new_array = my_subset.concat(my_array);

// array is sorted as desired
console.log(new_array);

First fix the data by making the numeric string a number and the boolean string a boolean: 首先通过将数字字符串设为数字,并将布尔字符串设为布尔值来修复数据:

for (const item of my_array) {
    item.pinned.status = JSON.parse(item.pinned.status);
    item.pinned.order = Number(item.pinned.order);
}

Now you won't have to compare them as strings. 现在,您不必将它们作为字符串进行比较。 Otherwise your approach is basically fine, you just forgot the most significant indicator whether an item should go to the top or not: its pinned.status . 否则,您的方法基本上没问题,您只是忘记了最重要的指示符,即某个项目是否应该到达顶部:它的pinned.status Compare by that first, so that any pinned item comes before any not pinned item. 首先进行比较,以使任何固定项目都在任何未固定项目之前。

my_array.sort(function(a, b) {
    return -(a.pinned.status - b.pinned.status) // reverse: true before false
    || (a.pinned.status // equal to b.pinned.status
      ? a.pinned.order - b.pinned.order
      : a.title.localeCompare(b.title));
});

 var my_array = [{ "title": "a", "pinned": { "status": true, "order": 1 } }, { "title": "d", "pinned": { "status": false, "order": 0 } }, { "title": "c", "pinned": { "status": true, "order": 0 } }, { "title": "b", "pinned": { "status": false, "order": 0 } } ]; my_array.sort(function(a, b) { return -(a.pinned.status - b.pinned.status) // reverse: true before false || (a.pinned.status // equal to b.pinned.status ? a.pinned.order - b.pinned.order : a.title.localeCompare(b.title)); }); console.log(my_array); 

You can also do 你也可以

my_array.sort(function(a, b) {
    return -(a.pinned.status - b.pinned.status) // reverse: true before false
    || a.pinned.order - b.pinned.order
    || a.title.localeCompare(b.title);
});

as not-pinned items have the same order ( NaN ) but the former is more explicit. 因为未固定的商品具有相同的顺序( NaN ),但前者更为明确。

Just try this: 尝试一下:

my_array.sort(function(a, b) {
    return a.title.localeCompare(b.title);
}).sort(function(a, b) {
    return a.pinned.order.localeCompare(b.pinned.order)
});

If you can use Lodash (utility library for Javascript) you can use orderBy or sortBy: 如果可以使用Lodash(Java实用程序库),则可以使用orderBy或sortBy:

use Lodash in project: 在项目中使用Lodash:

<script src="lodash.js"></script>

use orderBy to sort: 使用orderBy进行排序:

_.orderBy(my_array, [function(e) { return e.pinned.status}, 'title'], ['asc', 'asc']);

more info on orderBy 关于orderBy的更多信息

there you go: 你去那里:

 var my_array = [ { "title": "a", "pinned": { "status": "true", "order": "1" } }, { "title": "d", "pinned": { "status": "false", "order": "n/a" } }, { "title": "c", "pinned": { "status": "true", "order": "0" } }, { "title": "b", "pinned": { "status": "false", "order": "n/a" } } ]; var trueArr = []; var falseArr = []; var titleArr = []; var tempArr = [] for(var obj of my_array){ if(obj.pinned.status == "true"){ trueArr.push(obj); }else{ falseArr.push(obj); } } function sortArr(arr){ titleArr = []; tempArr = []; for(var obj of arr){ titleArr.push(obj.title); } titleArr = titleArr.sort(); for(var counter = 0; counter < arr.length; counter++){ tempArr.push(null); } for(var obj of arr){ tempArr[titleArr.indexOf(obj.title)] = obj; } for(counter = 0; counter < tempArr.length; counter++){ arr[counter] = tempArr[counter]; } } function addTrueFalseArr(arr){ for (var obj of arr){ my_array.push(obj) } } sortArr(trueArr); my_array = []; addTrueFalseArr(trueArr); sortArr(falseArr); addTrueFalseArr(falseArr); 

extracts all objects where pinned = true and puts them in an array. 提取pinned = true所有对象,并将它们放入数组中。 Then it does same for objects where pinned = false . 然后,对于pinned = false对象也是如此。 Then it sorts both arrays according to their titles (alphabetically), then sets original array to an empty array --> [] , then appends the true items to the original array and, finally, appends the false items. 然后,它会根据它们的标题(按字母顺序)对这两个数组进行排序,然后将原始数组设置为一个空数组-> [] ,然后将true项目附加到原始数组,最后附加false项目。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM