排序对象数组的单一键与日期值

我有一个具有几个键值对的对象数组,我需要根据'updated_at'对它们进行排序:

[
{
"updated_at" : "2012-01-01T06:25:24Z",
"foo" : "bar"
},
{
"updated_at" : "2012-01-09T11:25:13Z",
"foo" : "bar"
},
{
"updated_at" : "2012-01-05T04:13:24Z",
"foo" : "bar"
}
]

最有效的方法是什么?

493769 次浏览

我已经在这里回答了一个非常类似的问题:简单的函数对对象数组进行排序

对于这个问题,我创建了一个小函数,可以做你想做的事情:

function sortByKey(array, key) {
return array.sort(function(a, b) {
var x = a[key]; var y = b[key];
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
});
}

你可以使用Array.sort

下面是一个例子:
var arr = [{
"updated_at": "2012-01-01T06:25:24Z",
"foo": "bar"
},
{
"updated_at": "2012-01-09T11:25:13Z",
"foo": "bar"
},
{
"updated_at": "2012-01-05T04:13:24Z",
"foo": "bar"
}
]


arr.sort(function(a, b) {
var keyA = new Date(a.updated_at),
keyB = new Date(b.updated_at);
// Compare the 2 dates
if (keyA < keyB) return -1;
if (keyA > keyB) return 1;
return 0;
});


console.log(arr);

根据ISO格式的日期进行排序可能代价高昂,除非您将客户端限制为最新和最好的浏览器,这些浏览器可以通过对字符串进行日期解析来创建正确的时间戳。

如果你的输入是确定,并且你知道它将始终是yyyy-mm-ddThh:mm:ss和GMT (Z),你可以从每个成员中提取数字,并将它们作为整数进行比较

array.sort(function(a,b){
return a.updated_at.replace(/\D+/g,'')-b.updated_at.replace(/\D+/g,'');
});

如果日期可以有不同的格式,你可能需要为iso挑战的人添加一些东西:

Date.fromISO: function(s){
var day, tz,
rx=/^(\d{4}\-\d\d\-\d\d([tT ][\d:\.]*)?)([zZ]|([+\-])(\d\d):(\d\d))?$/,
p= rx.exec(s) || [];
if(p[1]){
day= p[1].split(/\D/).map(function(itm){
return parseInt(itm, 10) || 0;
});
day[1]-= 1;
day= new Date(Date.UTC.apply(Date, day));
if(!day.getDate()) return NaN;
if(p[5]){
tz= (parseInt(p[5], 10)*60);
if(p[6]) tz+= parseInt(p[6], 10);
if(p[4]== '+') tz*= -1;
if(tz) day.setUTCMinutes(day.getUTCMinutes()+ tz);
}
return day;
}
return NaN;
}
if(!Array.prototype.map){
Array.prototype.map= function(fun, scope){
var T= this, L= T.length, A= Array(L), i= 0;
if(typeof fun== 'function'){
while(i< L){
if(i in T){
A[i]= fun.call(scope, T[i], i, T);
}
++i;
}
return A;
}
}
}
}

下面是稍微修改过的david Brainer-Bankers回答版本,它按字母顺序或数字顺序排序,并确保以大写字母开头的单词不会排在以小写字母开头的单词之上(例如“apple,Early”将按此顺序显示)。

function sortByKey(array, key) {
return array.sort(function(a, b) {
var x = a[key];
var y = b[key];


if (typeof x == "string")
{
x = (""+x).toLowerCase();
}
if (typeof y == "string")
{
y = (""+y).toLowerCase();
}


return ((x < y) ? -1 : ((x > y) ? 1 : 0));
});
}
你可以创建一个闭包并以这种方式传递它 这是我的例子 < / p >
$.get('https://data.seattle.gov/resource/3k2p-39jp.json?$limit=10&$where=within_circle(incident_location, 47.594972, -122.331518, 1609.34)',
function(responce) {


var filter = 'event_clearance_group', //sort by key group name
data = responce;


var compare = function (filter) {
return function (a,b) {
var a = a[filter],
b = b[filter];


if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
};
};


filter = compare(filter); //set filter


console.log(data.sort(filter));
});

使用下划线js或lodash,

var arrObj = [
{
"updated_at" : "2012-01-01T06:25:24Z",
"foo" : "bar"
},
{
"updated_at" : "2012-01-09T11:25:13Z",
"foo" : "bar"
},
{
"updated_at" : "2012-01-05T04:13:24Z",
"foo" : "bar"
}
];


arrObj = _.sortBy(arrObj,"updated_at");

_.sortBy()返回一个新数组

引用http://underscorejs.org/#sortBy和 lodash docs https://lodash.com/docs#sortBy

在ES2015支持下,可以通过以下方式完成:

foo.sort((a, b) => a.updated_at < b.updated_at ? -1 : 1)

Array.sort ()方法对数组中的元素进行排序并返回数组。小心使用Array.sort (),因为它不是不可变的。对于不可变排序使用immutable-sort

此方法是使用ISO格式的当前updated_at对数组进行排序。我们使用new Data(iso_string).getTime()将ISO时间转换为Unix时间戳。Unix时间戳是一个数字,我们可以对它进行简单的计算。我们减去第一个和第二个时间戳,结果是;如果第一个时间戳大于第二个时间戳,则返回值为正数。如果第二个数字比第一个数字大,则返回值为负。如果两者相等,则返回值为零。这与内联函数所需的返回值完全一致。

ES6:

arr.sort((a,b) => new Date(a.updated_at).getTime() - new Date(b.updated_at).getTime());

ES5:

arr.sort(function(a,b){
return new Date(a.updated_at).getTime() - new Date(b.updated_at).getTime();
});

如果你将updated_at更改为unix时间戳,你可以这样做:

ES6:

arr.sort((a,b) => a.updated_at - b.updated_at);

ES5:

arr.sort(function(a,b){
return a.updated_at - b.updated_at;
});

在撰写本文时,现代浏览器还不支持ES6。要在现代浏览器中使用ES6,请使用巴别塔将代码编译到ES5。期待在不久的将来浏览器对ES6的支持。

Array.sort ()应该接收3种可能结果之一的返回值:

  • 正数(第一项>第二项)
  • 负数(第一项<第二项)
  • 如果两项相等,则为0
注意,内联函数的返回值可以是任何值 正数或负数。Array.Sort()并不关心 返回编号为。它只关心返回值是否为正,

对于不可变排序:(ES6中的例子)

const sort = require('immutable-sort');
const array = [1, 5, 2, 4, 3];
const sortedArray = sort(array);

你也可以这样写:

import sort from 'immutable-sort';
const array = [1, 5, 2, 4, 3];
const sortedArray = sort(array);

import-from是在ES6中包含javascript的一种新方法,它使你的代码看起来非常干净。我个人的最爱。

不可变排序不会改变源数组,而是返回一个新数组。建议在不可变数据上使用const

只是另一种更< em >数学< / em >的方式,做同样的事情,但更短的:

arr.sort(function(a, b){
var diff = new Date(a.updated_at) - new Date(b.updated_at);
return diff/(Math.abs(diff)||1);
});

或者在光滑的lambda箭头样式中:

arr.sort((a, b) => {
var diff = new Date(a.updated_at) - new Date(b.updated_at);
return diff/(Math.abs(diff)||1);
});

此方法可用于任何数字输入

今天,@knowbody (https://stackoverflow.com/a/42418963/6778546)和@Rocket Hazmat (https://stackoverflow.com/a/8837511/6778546)的答案可以结合起来提供ES2015支持和正确的日期处理:

arr.sort((a, b) => {
const dateA = new Date(a.updated_at);
const dateB = new Date(b.updated_at);
return dateA - dateB;
});

正如答案的状态,你可以使用Array.sort

arr.sort(function(a,b){return new Date(a.updated_at) - new Date(b.updated_at)})

arr = [
{
"updated_at" : "2012-01-01T06:25:24Z",
"foo" : "bar"
},
{
"updated_at" : "2012-01-09T11:25:13Z",
"foo" : "bar"
},
{
"updated_at" : "2012-01-05T04:13:24Z",
"foo" : "bar"
}
];
arr.sort(function(a,b){return new Date(a.updated_at) - new Date(b.updated_at)});
console.log(arr);

为了完整起见,这里有一个sortBy的简短泛型实现:

function sortBy(list, keyFunc) {
return list.sort((a,b) => keyFunc(a) - keyFunc(b));
}


sortBy([{"key": 2}, {"key": 1}], o => o["key"])

注意,这使用了就地排序的数组sort方法。 对于副本,您可以使用arr.concat()或arr.slice(0)或类似的方法来创建副本

这样我们就可以传递一个用于排序的键函数

Array.prototype.sortBy = function(key_func, reverse=false){
return this.sort( (a, b) => {
var keyA = key_func(a),
keyB = key_func(b);
if(keyA < keyB) return reverse? 1: -1;
if(keyA > keyB) return reverse? -1: 1;
return 0;
});
}

例如,如果我们有

var arr = [ {date: "01/12/00", balls: {red: "a8",  blue: 10}},
{date: "12/13/05", balls: {red: "d6" , blue: 11}},
{date: "03/02/04", balls: {red: "c4" , blue: 15}} ]

我们可以

arr.sortBy(el => el.balls.red)
/* would result in
[ {date: "01/12/00", balls: {red: "a8", blue: 10}},
{date: "03/02/04", balls: {red: "c4", blue: 15}},
{date: "12/13/05", balls: {red: "d6", blue: 11}} ]
*/

arr.sortBy(el => new Date(el.date), true)   // second argument to reverse it
/* would result in
[ {date: "12/13/05", balls: {red: "d6", blue:11}},
{date: "03/02/04", balls: {red: "c4", blue:15}},
{date: "01/12/00", balls: {red: "a8", blue:10}} ]
*/

arr.sortBy(el => el.balls.blue + parseInt(el.balls.red[1]))
/* would result in
[ {date: "12/13/05", balls: {red: "d6", blue:11}},    // red + blue= 17
{date: "01/12/00", balls: {red: "a8", blue:10}},    // red + blue= 18
{date: "03/02/04", balls: {red: "c4", blue:15}} ]   // red + blue= 19
*/

数据导入

[
{
"gameStatus": "1",
"userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
"created_at": "2018-12-20 11:32:04"
},
{
"gameStatus": "0",
"userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
"created_at": "2018-12-19 18:08:24"
},
{
"gameStatus": "2",
"userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
"created_at": "2018-12-19 18:35:40"
},
{
"gameStatus": "0",
"userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
"created_at": "2018-12-19 10:42:53"
},
{
"gameStatus": "2",
"userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
"created_at": "2018-12-20 10:54:09"
},
{
"gameStatus": "0",
"userId": "1a2fefb0-5ae2-47eb-82ff-d1b2cc27875a",
"created_at": "2018-12-19 18:46:22"
},
{
"gameStatus": "1",
"userId": "7118ed61-d8d9-4098-a81b-484158806d21",
"created_at": "2018-12-20 10:50:48"
}
]

由高到低

arr.sort(function(a, b){
var keyA = new Date(a.updated_at),
keyB = new Date(b.updated_at);
// Compare the 2 dates
if(keyA < keyB) return -1;
if(keyA > keyB) return 1;
return 0;
});

例如Asc Order

[
{
"gameStatus": "0",
"userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
"created_at": "2018-12-19 10:42:53"
},
{
"gameStatus": "0",
"userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
"created_at": "2018-12-19 18:08:24"
},
{
"gameStatus": "2",
"userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
"created_at": "2018-12-19 18:35:40"
},
{
"gameStatus": "0",
"userId": "1a2fefb0-5ae2-47eb-82ff-d1b2cc27875a",
"created_at": "2018-12-19 18:46:22"
},
{
"gameStatus": "1",
"userId": "7118ed61-d8d9-4098-a81b-484158806d21",
"created_at": "2018-12-20 10:50:48"
},
{
"gameStatus": "2",
"userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
"created_at": "2018-12-20 10:54:09"
},
{
"gameStatus": "1",
"userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
"created_at": "2018-12-20 11:32:04"
}
]

降序为

arr.sort(function(a, b){
var keyA = new Date(a.updated_at),
keyB = new Date(b.updated_at);
// Compare the 2 dates
if(keyA > keyB) return -1;
if(keyA < keyB) return 1;
return 0;
});

描述顺序示例

[
{
"gameStatus": "1",
"userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
"created_at": "2018-12-20 11:32:04"
},
{
"gameStatus": "2",
"userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
"created_at": "2018-12-20 10:54:09"
},
{
"gameStatus": "1",
"userId": "7118ed61-d8d9-4098-a81b-484158806d21",
"created_at": "2018-12-20 10:50:48"
},
{
"gameStatus": "0",
"userId": "1a2fefb0-5ae2-47eb-82ff-d1b2cc27875a",
"created_at": "2018-12-19 18:46:22"
},
{
"gameStatus": "2",
"userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
"created_at": "2018-12-19 18:35:40"
},
{
"gameStatus": "0",
"userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
"created_at": "2018-12-19 18:08:24"
},
{
"gameStatus": "0",
"userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
"created_at": "2018-12-19 10:42:53"
}
]
  • 使用Array.sort()对数组进行排序
  • 使用传播算子 ()克隆数组,使函数纯
  • 按所需键排序(updated_at)
  • 将日期字符串转换为日期对象
  • Array.sort()通过从current和next项目减去两个属性来工作,如果它是一个可以执行无节奏操作的数字/对象
const input = [
{
updated_at: '2012-01-01T06:25:24Z',
foo: 'bar',
},
{
updated_at: '2012-01-09T11:25:13Z',
foo: 'bar',
},
{
updated_at: '2012-01-05T04:13:24Z',
foo: 'bar',
}
];


const sortByUpdatedAt = (items) => [...items].sort((itemA, itemB) => new Date(itemA.updated_at) - new Date(itemB.updated_at));


const output = sortByUpdatedAt(input);


console.log(input);
/*
[ { updated_at: '2012-01-01T06:25:24Z', foo: 'bar' }, 
{ updated_at: '2012-01-09T11:25:13Z', foo: 'bar' }, 
{ updated_at: '2012-01-05T04:13:24Z', foo: 'bar' } ]
*/
console.log(output)
/*
[ { updated_at: '2012-01-01T06:25:24Z', foo: 'bar' }, 
{ updated_at: '2012-01-05T04:13:24Z', foo: 'bar' }, 
{ updated_at: '2012-01-09T11:25:13Z', foo: 'bar' } ]
*/

我已经在Typescript中创建了一个排序函数,我们可以使用它来搜索字符串,日期和对象数组中的数字。它还可以对多个字段进行排序。

export type SortType = 'string' | 'number' | 'date';
export type SortingOrder = 'asc' | 'desc';


export interface SortOptions {
sortByKey: string;
sortType?: SortType;
sortingOrder?: SortingOrder;
}




class CustomSorting {
static sortArrayOfObjects(fields: SortOptions[] = [{sortByKey: 'value', sortType: 'string', sortingOrder: 'desc'}]) {
return (a, b) => fields
.map((field) => {
if (!a[field.sortByKey] || !b[field.sortByKey]) {
return 0;
}


const direction = field.sortingOrder === 'asc' ? 1 : -1;


let firstValue;
let secondValue;


if (field.sortType === 'string') {
firstValue = a[field.sortByKey].toUpperCase();
secondValue = b[field.sortByKey].toUpperCase();
} else if (field.sortType === 'number') {
firstValue = parseInt(a[field.sortByKey], 10);
secondValue = parseInt(b[field.sortByKey], 10);
} else if (field.sortType === 'date') {
firstValue = new Date(a[field.sortByKey]);
secondValue = new Date(b[field.sortByKey]);
}
return firstValue > secondValue ? direction : firstValue < secondValue ? -(direction) : 0;


})
.reduce((pos, neg) => pos ? pos : neg, 0);
}
}
}

用法:

const sortOptions = [{
sortByKey: 'anyKey',
sortType: 'string',
sortingOrder: 'asc',
}];


arrayOfObjects.sort(CustomSorting.sortArrayOfObjects(sortOptions));

你可以使用Lodash实用程序库来解决这个问题(它是一个非常有效的库):

const data = [{
"updated_at": "2012-01-01T06:25:24Z",
"foo": "bar"
},
{
"updated_at": "2012-01-09T11:25:13Z",
"foo": "bar"
},
{
"updated_at": "2012-01-05T04:13:24Z",
"foo": "bar"
}
]


const ordered = _.orderBy(
data,
function(item) {
return item.updated_at;
}
);


console.log(ordered)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

You can find documentation here: https://lodash.com/docs/4.17.15#orderBy

我面对同样的事情,所以我用一个通用的为什么处理这个,我为此建立了一个函数:

//example:
//array: [{name: 'idan', workerType: '3'}, {name: 'stas', workerType: '5'}, {name: 'kirill', workerType: '2'}]
//keyField: 'workerType'
// keysArray: ['4', '3', '2', '5', '6']
sortByArrayOfKeys = (array, keyField, keysArray) => {
array.sort((a, b) => {
const aIndex = keysArray.indexOf(a[keyField])
const bIndex = keysArray.indexOf(b[keyField])
if (aIndex < bIndex) return -1;
if (aIndex > bIndex) return 1;
return 0;
})
}

我说得有点晚了,但在2021年,正确的答案是使用Intl.Collatorupdated_at是一个ISO-8601字符串,因此可以作为字符串进行排序。转换为Date是浪费时间,因此手动执行if比较以返回0、1或-1也是浪费时间。

const arr = [
{
"updated_at": "2012-01-01T06:25:24Z",
"foo": "bar"
},
{
"updated_at": "2012-01-09T11:25:13Z",
"foo": "bar"
},
{
"updated_at": "2012-01-05T04:13:24Z",
"foo": "bar"
}
];


const { compare } = Intl.Collator('en-US');
arr.sort((a, b) => compare(a.updated_at, b.updated_at));

Intl.Collator返回一个函数,可以用作#Array.sortcompareFunction。因为我们正在对对象排序,所以我们调用compare,并使用我们想要排序的键的值。

注意,如果我们对一个字符串数组排序,我们可以简单地这样做:

arr.sort(compare);

还要注意,正如其他人指出的那样,sort将改变原始数组。如果这是不可取的,您可能希望首先克隆它。在2021年,你可以这样做:

[...arr].sort((a, b) => compare(a.updated_at, b.updated_at));