Сортировка массива объектов по одному ключу с датой

У меня есть массив объектов с несколькими парами значений ключей, и мне нужно отсортировать их на основе "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"
    }
]

Какой самый эффективный способ сделать это?

Ответ 1

Вы можете использовать Array.sort.

Здесь пример (непроверенный):

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

Ответ 2

Я уже ответил на действительно похожий вопрос: Простая функция для сортировки массива объектов

Для этого вопроса я создал эту небольшую функцию, которая может делать то, что вы хотите:

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

Ответ 3

Метод Array.sort() сортирует элементы массива на месте и возвращает массив. Будьте осторожны с Array.sort(), поскольку это не Immutable. Для неизменной сортировки используйте immutable-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);

Импорт из вашего браузера - это новый способ включить javascript в ES6 и сделать ваш код очень чистым. Мой личный фаворит.

Неизбежная сортировка не мутирует исходный массив, а возвращает новый массив. Использование const рекомендуется по неизменяемым данным.

Ответ 4

Здесь слегка измененная версия @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));
    });
}

Ответ 5

Используйте подчеркивание 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

Ответ 6

С поддержкой ES2015 это можно сделать:

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

Ответ 7

Как говорится в этом ответе, вы можете использовать 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);

Ответ 8

Еще один, более математический, способ сделать то же самое, но короче:

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

или в стиле стрелки лямбда:

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

Этот метод может быть выполнен с помощью любого числового ввода

Ответ 9

Я создал сортировочную функцию в 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));

Ответ 10

Сортировка по дате, отформатированной в формате ISO, может быть дорогостоящей, если вы не ограничите клиентов последними и лучшими браузерами, которые могут создать правильную метку времени с помощью Date-parsing строки.

Если вы уверены вашего ввода, а знаете, он всегда будет 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,'');
});

Если дату можно форматировать по-разному, вам может потребоваться добавить что-то для людей с ограниченными рисками:

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

Ответ 11

На сегодняшний день ответы @knowbody (fooobar.com/questions/44381/...) и @Rocket Hazmat (fooobar.com/questions/44381/...) могут быть объединены для обеспечения поддержки ES2015 и правильной обработки даты:

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

Ответ 12

При этом мы можем передать ключевую функцию для сортировки

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

Ответ 13

Данные импортированы

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

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

Пример для Desc Order

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

Ответ 14

Вы можете создать закрытие и передать его таким образом вот мой пример работы

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

Ответ 15

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

Ответ 16

Для полноты здесь возможна краткая обобщенная реализация sortBy:

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

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

Обратите внимание, что здесь используется метод сортировки массивов, который сортирует по месту. для копирования вы можете использовать arr.concat() или arr.slice(0) или аналогичный метод для создания копии.

Ответ 17

  • Используйте 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' } ]
*/