按单键按日期值对对象数组进行排序


257

我有一个带有几个键值对的对象数组,我需要根据'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"
    }
]

这样做最有效的方法是什么?


@Topener该链接似乎是有关PHP的问题
David Brainer 2012年

我的错误..没有正确地读它
勒内锅

Answers:


337

您可以使用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);


17
您不能使用keyA - keyB(或可能keyB - keyA)吗?日期对象具有valueOf()方法。
soktinpk

返回 Updated_at <b。Updated_at?1:-1对我有用。无需解析为日期格式。
Oliversisson

a-b如果您想避免长代码,那么做到这一点的能力就非常重要。尽管在这种情况下长代码不一定是不好的,但我认为冗长的代码使其更难理解。我目前正在使用values.sort((a,b)=>a.attr-b.attr)。每次需要对数组进行排序时,都必须写5行。
AnnanFay

此示例无效,并且进行了许多不必要的计算。排序可以采用任何正数或负数作为有效结果。不需要强制将其设为1,0,-1的额外计算,只需在每次执行时添加额外的计算即可。
Patrick W. McMahon

可以让您大为高兴
Andy

158

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

对于这个问题,我创建了这个小功能,可以执行您想要的操作:

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));
    });
}


2
您将如何扭转呢?

4
要使其不区分大小写,可以将.toLowerCase()添加到x和y变量
Jacob van Lingen

4
要反转这样的排序功能,只需将结果乘以-1:)
Svish进行

5
或者只是获取输出并使用该array = array.reverse()函数。
卢克·史蒂文森

31

所述的Array.sort()方法进行排序的阵列的代替元素并返回数组。注意Array.sort()并非不可变的。对于不可变排序,请使用不可变排序

此方法是使用您当前updated_at的ISO格式对数组进行排序。我们用于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,请使用babel将代码转换为ES5。期望浏览器在不久的将来对ES6的支持。

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

  • 正数(第一项>第二项)
  • 负数(第一项<第二项)
  • 如果两项相等则为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是一种将JavaScript包含在ES6中的新方法,并使您的代码看起来很干净。我个人的最爱。

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


19

这是@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));
    });
}

3
如果a [key]和b [key]都不都是字符串,建议的解决方案可能会给出错误。我建议将y = y.toLowerCase()替换为y =(“” + y).toLowerCase()
user8074 '16

sort可以接受任何正数或负数作为有效返回值。您需要进行额外的计算来强制将其设为1,0,-1。您使一个简单的返回值复杂化了。最好不要添加不做任何事情的额外计算。
Patrick W. McMahon


6

借助ES2015支持,可以通过以下方式实现:

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

1
如果将<替换为-并删除',则不需要内联?1:1" ,你会得到一个有效的返回这个例子移动的项目,可以相等,并且因此可能会出现意想不到的结果等于一个项目应返回0。
帕特里克·W·麦克马洪

感谢您的解释
-Knowbody

如果updated_at是ISO时间,则将不起作用。此示例假定使用Unix时间戳,但OP以ISO格式发布了数据。因此,您必须转换为Unix时间戳进行比较。可以这样做,new Date(iso_str).getTime()这将返回Unix时间戳。
Patrick W. McMahon

5

数据导入

[
    {
        "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;
});

升序示例

[
    {
        "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"
    }
]

3

由于答案的状态,你可以使用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);


2

这是另一种更数学的方法来完成相同的任务,但更短

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);
});

可以使用任何数字输入来完成此方法


被低估的答案
two7s_clash


2

我已经在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));

1

按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;
        }
    }
}
}

2
你不能只用Date.parse吗?
火箭Hazmat 2012年

1

为了完整起见,以下是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)或类似方法来创建副本。


1

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

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
*/

1

您可以使用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>

您可以在此处找到文档:https : //lodash.com/docs/4.17.15#orderBy


0

您可以创建一个闭包并以这种方式传递它, 这是我的示例工作

$.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));
});

0
var months = [
    {
        "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"
    }];
months.sort((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(months);

0
  • 使用Array.sort()排序数组
  • 使用传播算子)复制数组以使函数纯净
  • 按所需键排序(updated_at
  • 将日期字符串转换为日期对象
  • Array.sort() 通过从当前项和下一项减去两个属性(如果它是可以执行心律失常操作的数字/对象)来工作
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' } ]
*/

0

我面对同样的事情,所以我用一个通用的原因来处理这个问题,为此我建立了一个函数:

//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;
    })
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.