web-dev-qa-db-fra.com

Trier un tableau d'objets par clé unique avec valeur de date

J'ai un tableau d'objets avec plusieurs paires de valeurs de clé et je dois les trier en fonction de '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"
    }
]

Quel est le moyen le plus efficace de le faire?

192
user1022241

Vous pouvez utiliser Array.sort .

Voici un exemple (non testé):

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;
});
266
Rocket Hazmat

J'ai déjà répondu à une question très similaire ici: Fonction simple pour trier un tableau d'objets

Pour cette question, j'ai créé cette petite fonction qui pourrait faire ce que vous voulez:

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));
    });
}
142
David Brainer

Voici une version légèrement modifiée de La réponse de @David Brainer-Bankers est triée alphabétiquement par chaîne ou numérique par numéro et garantit que les mots commençant par des majuscules ne sont pas triés par dessus des mots commençant par une lettre minuscule (par exemple, " Apple, Early "serait affiché dans cet ordre).

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));
    });
}
17
Brad Parks

La méthode Array.sort () trie les éléments d'un tableau à la place et renvoie le tableau. Soyez prudent avec Array.sort () car ce n'est pas Immuable . Pour le type immuable, utilisez immutable-sort .

Cette méthode consiste à trier le tableau en utilisant votre updated_at actuel au format ISO. Nous utilisons new Data(iso_string).getTime() pour convertir l'heure ISO en horodatage Unix. Un timestamp Unix est un nombre sur lequel nous pouvons faire des calculs simples. Nous soustrayons le premier et le deuxième horodatage du résultat; Si le premier horodatage est supérieur à la seconde, le numéro de retour sera positif. Si le deuxième nombre est plus grand que le premier, la valeur de retour sera négative. Si les deux sont identiques, le retour sera zéro. Cela correspond parfaitement aux valeurs de retour requises pour la fonction inline.

Pour ES6 :

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

Pour ES5 :

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

Si vous changez votre updated_at pour qu'il soit un horodatage Unix, vous pouvez le faire:

Pour ES6 :

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

Pour ES5 :

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

Au moment de cet article, les navigateurs modernes ne supportent pas ES6. Pour utiliser ES6 dans les navigateurs modernes, utilisez babel pour transcrire le code en ES5. Attendez-vous à un support du navigateur pour ES6 dans un avenir proche.

Array.sort () doit récupérer une valeur de retour correspondant à l'un des 3 résultats possibles:

  • Un nombre positif (premier élément> deuxième élément)
  • Un nombre négatif (premier élément <deuxième élément)
  • 0 si les deux éléments sont égaux

Notez que la valeur de retour sur la fonction inline peut être n'importe quel nombre positif ou négatif. Array.Sort () ne se soucie pas de ce que le Le numéro de retour est. Cela ne sert que si la valeur de retour est positive, négatif ou nul.

Pour le tri immuable: (exemple dans ES6)

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

Vous pouvez aussi l'écrire de cette façon:

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

L'importation à partir de vous est une nouvelle façon d'inclure javascript dans ES6 et donne à votre code une apparence très propre. Mon préféré 

Le tri immuable ne mute pas le tableau source mais renvoie un nouveau tableau. L'utilisation de const est recommandée sur des données immuables.

17
Patrick W. McMahon

Utilisez des traits de soulignement js ou 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() renvoie un nouveau tableau

référez-vous http://underscorejs.org/#sortBy et lodash docs https://lodash.com/docs#sortBy

13
Mohammed Safeer

J'ai créé une fonction de tri dans TypeScript que nous pouvons utiliser pour rechercher des chaînes, des dates et des nombres dans un tableau d'objets. Il peut également trier sur plusieurs champs.

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

Usage:

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

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

Juste une autre manière plusmathématique, de faire la même chose mais plus courte :

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

ou dans le style de flèche lambda lisse:

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

Cette méthode peut être réalisée avec n'importe quelle entrée numérique 

2
Danny Mor

Avec le support ES2015, cela peut être fait par:

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

Trier par une date au format ISO peut coûter cher, sauf si vous limitez les clients aux navigateurs les plus récents et les meilleurs, ce qui permet de créer un horodatage correct en analysant la date par la chaîne.

Si vous êtes sûr de votre entrée, et que vous savez ce sera toujours aaaa-mm-jjThh: mm: ss et GMT (Z), vous pouvez extraire les chiffres de chaque membre et les comparer comme des entiers

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

Si la date peut être formatée différemment, vous devrez peut-être ajouter quelque chose pour les personnes aux problèmes 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;
        }
    }
}
}
1
kennebec

Données importées

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

POUR ordre croissant

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

Exemple pour Ordre 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"
    }
]

POUR ordre décroissant

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

Exemple pour 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"
    }
]
1
Anandan K

Quant à aujourd'hui, réponses de @knowbody ( https://stackoverflow.com/a/42418963/6778546 ) et de @Rocket Hazmat ( https://stackoverflow.com/a/8837511/6778546 ) peuvent être combinés pour assurer la prise en charge ES2015 et le traitement correct des dates:

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

Pour être complet, voici une courte implémentation générique de sortBy:

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

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

Notez que cela utilise la méthode de tri des tableaux qui trie sur place . Pour une copie, vous pouvez utiliser arr.concat () ou arr.slice (0) ou une méthode similaire pour créer une copie.

0
Legion
  • Utilisez Array.sort() pour trier un tableau
  • Cloner un tableau en utilisant opérateur d'étalement () pour rendre la fonction pure
  • Trier par clé souhaitée (updated_at)
  • Convertir la chaîne de date en objet date
  • Array.sort() fonctionne en soustrayant deux propriétés des éléments actuel et suivant s'il s'agit d'un nombre/objet sur lequel vous pouvez effectuer des opérations arythmiques
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
marcobiedermann
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
Prasad

Avec cela, nous pouvons passer une fonction clé à utiliser pour le tri

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

Alors par exemple si nous avons

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

Nous pouvons faire

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

ou 

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

ou

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

Vous pouvez créer une fermeture et la passer de cette façon voici mon exemple qui fonctionne

$.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
Michael Guild