对数组进行排序以在数组中首先包含特定项

时间:2011-08-07 16:32:28

标签: javascript arrays sorting

我有一个阵列:

[{flag: true, other: 1},
 {flag: true, other: 2},
 {flag: false, other: 3},
 {flag: true, other: 4},
 {flag: true, other: 5},
 {flag: true, other: 6},
 {flag: false, other: 7}]

我想要这个:

[{flag: false, other: 3},
 {flag: false, other: 7},
 {flag: true, other: 1},
 {flag: true, other: 2},
 {flag: true, other: 4},
 {flag: true, other: 5},
 {flag: true, other: 6}]

基本上我希望如果array[2].flag === false(或我选择的任何其他值)匹配元素首先放在数组中,但是在之前的匹配元素之后。 不匹配的元素保持原来的顺序。

外观顺序很重要。

如何在JavaScript中做到最好?

10 个答案:

答案 0 :(得分:13)

ECMAScript6引入的Spread syntax(例如,...object)使用数组reduce方法使这相对简单:

const arr = [
  { flag: true, other: 1 },
  { flag: true, other: 2 },
  { flag: false, other: 3 },
  { flag: true, other: 4 },
  { flag: true, other: 5 },
  { flag: true, other: 6 },
  { flag: false, other: 7 }
];

const sortedArr = arr.reduce((acc, element) => {
  if (element.flag === false) {
    return [element, ...acc];
  }
  return [...acc, element];
}, []);

我发现这example of extended parameter handling非常有帮助。

答案 1 :(得分:8)

编写自定义排序函数并使用该标志来提高优先级:

array.sort(function(a,b) {
  if (!a['flag'] && b['flag'])
    return 1;
  if (a['flag'] && !b['flag'])
    return -1;
  return a['other'] - b['other']
});

答案 2 :(得分:7)

这实际上并不是排序。您可以循环遍历数组两次并构建一个新数组:

var result = [];
for (var i = 0; i < arr.length; i++) {
  if (arr[i].flag === false) {
    result.push(arr[i]);
  }
}
for (var i = 0; i < arr.length; i++) {
  if (!arr[i].flag === false) {
    result.push(arr[i]);
  }
}

您也可以使用两个结果数组和一个循环,并连接结果:

var result1 = [], result2 = [];
for (var i = 0; i < arr.length; i++) {
  if (arr[i].flag === false) {
    result1.push(arr[i]);
  } else {
    result2.push(arr[i]);
  }
}
var result = result1.concat(result2);

答案 3 :(得分:4)

一种更简单,更优雅的方法是通过两次构建一个包含旧数组内容的新数组:一次被flag: true过滤,一次被flag: false过滤。总共看起来像:

const originalArray = [
    {flag: true, other: 1},
    {flag: true, other: 2},
    {flag: false, other: 3},
    {flag: true, other: 4},
    {flag: true, other: 5},
    {flag: true, other: 6},
    {flag: false, other: 7}
];

const sortedArray = [
    ...originalArray.filter(({flag}) => flag),
    ...originalArray.filter(({flag}) => !!flag)
];

在我看来,它很容易阅读,并且(根据我的测量结果)是一种性能很好的解决方案。


性能比较:

我发现the most upvoted answer使用arr.reduce()的速度比我的解决方案慢20倍。我使用ES6 Console进行比较,也可以自行测试!

衡量最喜欢的array.reduce()方式:

const arr = [
  { flag: true, other: 1 },
  { flag: true, other: 2 },
  { flag: false, other: 3 },
  { flag: true, other: 4 },
  { flag: true, other: 5 },
  { flag: true, other: 6 },
  { flag: false, other: 7 }
];

new Array(11).fill().forEach(x => arr.push(...arr));

console.time();

const reducedArr = arr.reduce((acc, element) => {
  if (element.flag === false) {
    return [element, ...acc];
  }
  return [...acc, element];
}, []);

console.timeEnd(); // RESULTS: between 285-350ms

以我的array.filter()方式进行测量:

const arr = [
  { flag: true, other: 1 },
  { flag: true, other: 2 },
  { flag: false, other: 3 },
  { flag: true, other: 4 },
  { flag: true, other: 5 },
  { flag: true, other: 6 },
  { flag: false, other: 7 }
];

new Array(11).fill().forEach(x => arr.push(...arr));

console.time();

const rebuiltArray = [
  ...arr.filter(x => !!x.flag),
  ...arr.filter(x => !x.flag)
];

console.timeEnd(); // RESULTS: between 6-20ms

答案 4 :(得分:1)

我认为这有点简单。 因为javascript将true视为1而false视为0,您可以使用它们来创建这样的比较器,

var comp = function(a,b){
    return a.flag*1 - b.flag*1;
}

然后您可以使用此比较器对数组进行排序

var arr = [{flag: true, other: 1},
         {flag: true, other: 2},
         {flag: false, other: 3},
         {flag: true, other: 4},
         {flag: true, other: 5},
         {flag: true, other: 6},
         {flag: false, other: 7}];
arr.sort(comp);

答案 5 :(得分:0)

sort方法可以使用一个可选的sortFunction作为参数,您可以使用它来定义排序后元素的排序

http://www.w3schools.com/jsref/jsref_sort.asp

答案 6 :(得分:0)

由于您要选择某些数组项但保持其原始顺序,因此您需要filter()方法。此功能是extension to the standard,因此您可能需要使用该页面提供的填充程序,具体取决于您支持的浏览器。

(当我第一次阅读你的问题时,我认为你想根据标志进行排序,然后根据价值进行排序;为此你可以使用内置的sort()方法。)

var input = [{flag: true, other: 1},
             {flag: true, other: 2},
             {flag: false, other: 3},
             {flag: true, other: 4},
             {flag: true, other: 5},
             {flag: true, other: 6},
             {flag: false, other: 7}]
var false_items = input.filter(
        function(val, idx, arr) {
            return (val["flag"] == false);
        });
var true_items = input.filter(
        function(val, idx, arr) {
            return (val["flag"] == true);
        });

var sorted = false_items.concat(true_items);

答案 7 :(得分:0)

一种解决方案可以是根据flag对数组进行排序,然后根据other

var a = [{flag: true, other: 1},
 {flag: true, other: 2},
 {flag: false, other: 3},
 {flag: true, other: 4},
 {flag: true, other: 5},
 {flag: true, other: 6},
 {flag: false, other: 7}];

a.sort((a, b)=> a.flag - b.flag).sort((a,b) => a.other - b.other);

答案 8 :(得分:0)

您可以按值的增量进行排序。

  1. flag排序。如果是1,则布尔值将转换为true;如果是{{1},则布尔值将转换为0
  2. false.排序。

other
var array = [{flag: true, other: 1 }, { flag: true, other: 2 }, { flag: false, other: 3 }, { flag: true, other: 4 }, { flag: true, other: 5 }, { flag: true, other: 6 }, { flag: false, other: 7 }];

array.sort((a, b) =>
    a.flag - b.flag ||
    a.other - b.other
);

console.log(array);

答案 9 :(得分:-1)

arr = arr.sort(function(a, b) { // sort the array using a custom function,
                                // which is called a number of times to
                                // determine the new order. a and b are two
                                // elements to compare. JavaScript uses the
                                // return value to determine the new order:
                                // 1  - a should come later than b
                                // -1 - a should come earlier than b
                                // 0  - they should stay in their current order
    return a.flag === true && b.flag === false
            ? 1 // if a is true and b is false a should come later on
            : a.flag === false && b.flag === true
               ? -1 // if a is false and b is true a should come earlier
               : a.other > b.other
                  ? 1 // if a.other > b.other, a must come later on
                  : a.other < b.other
                    ? -1 // if a.other < b.other, a must come earlier
                    : 0; // otherwise they are equal, so they have no order difference
});