admin管理员组文章数量:1136159
I've got an array as such:
[{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}]
I want to have this:
[{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}]
Basically I want that if array[2].flag === false
(or any other value I choose) the matching element gets placed first in the array, but after previous matching elements.
The elements that do not match, remain in the same order they were in originally.
Order of appearance is important.
How to do this best in JavaScript?
I've got an array as such:
[{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}]
I want to have this:
[{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}]
Basically I want that if array[2].flag === false
(or any other value I choose) the matching element gets placed first in the array, but after previous matching elements.
The elements that do not match, remain in the same order they were in originally.
Order of appearance is important.
How to do this best in JavaScript?
Share Improve this question edited Aug 7, 2011 at 16:36 pimvdb 155k80 gold badges311 silver badges356 bronze badges asked Aug 7, 2011 at 16:32 duck degenduck degen 1,2232 gold badges12 silver badges17 bronze badges 4 |11 Answers
Reset to default 50The Spread syntax introduced with ECMAScript6 (e.g., [...object]
) makes this relatively straightforward using an Array's reduce
method:
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) {
return [element, ...acc];
}
return [...acc, element];
}, []);
I found this example of extended parameter handling really helpful.
A simpler and more elegant way to do is by building a new array by filtering the old one twice: once filtered by flag: true
and once by flag: false
. All together it would look like:
// THE INITIAL ARRAY:
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}
];
// THE SORTED ARRAY:
const sortedArray = [
...originalArray.filter(({flag}) => flag),
...originalArray.filter(({flag}) => !flag)
];
In my opinion it is way easier for a human to read than using comparer or reducer functions, and (based on measurements) it is also a pretty well-performing solution.
A performance comparison:
I saw that the most upvoted answer using arr.reduce()
performs around 20x slower than this solution. I used ES6 Console for comparison, feel free to test it yourself too!
Measuring the array.reduce()
way:
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 }
];
// Lets multiple the array items 11 times to increase the looping process:
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
Measuring the array.filter()
way:
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 }
];
// Lets multiple the array items 11 times to increase the looping process:
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
Write a custom sort function that uses the flag to increase the sort priority:
array.sort(function(a,b) {
if (!a['flag'] && b['flag'])
return 1;
if (a['flag'] && !b['flag'])
return -1;
return a['other'] - b['other']
});
Basically, I'm assuming that an entry in the list with the flag set takes priority over an item without the flag. So if a doesn't have the flag set and b does, return 1 (select b). If a does and b doesn't return -1 (select a).
In the case where both have the flag set or both don't, cmp as normal.
This isn't actually sorting. You can just loop through the array twice and build a new array:
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]);
}
}
You can also do it with two result arrays and one loop, and concatenate the results:
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);
I think this is a little simple. Because javascript treats true as 1 and false as 0 you can use them to create a comparator like this,
var comp = function(a,b){
return a.flag*1 - b.flag*1;
}
and then you can use this comparator to sort the array
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);
You could sort with the deltas of the values.
- Sort by
flag
. The boolean values are converted to1
, iftrue
or0
, iffalse.
- Sort by
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);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Since you want to select certain array items but keep them in their original order, you want the filter()
method. This function is an extension to the standard, so you may need to use the shim provided at that page depending on what browsers you’re supporting.
(When I first read your question I thought that you wanted to sort based on the flag, and then based on value; for that you could use the built-in sort()
method.)
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);
The sort method can take an optional sortFunction as a parameter that you can use to define the ordering of elements after the sort
http://www.w3schools.com/jsref/jsref_sort.asp
One solution can be to sort the array on the basis of flag
and then by the 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);
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}
];
sorted = Array.from(new Set([
...a.filter(el => !el.flag),
...a
]).values());
console.log(sorted)
First filter the rows with flag set to false. Then add the other elements using a Set to avoid duplicates and then generate the array back from its values.
Useful if you want to handpick a few elements at the top in result and leave the rest in original order. The .filter line can be replaced by a list of hand-picked elements.
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
});
本文标签: javascriptSort an array to have specific items first in the arrayStack Overflow
版权声明:本文标题:javascript - Sort an array to have specific items first in the array - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736944622a1957229.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
flag
offalse
, relative to each other? – Armen Michaeli Commented Aug 7, 2011 at 16:37