3
votes

Comment trier un tableau imbriqué en fonction de la valeur avec lodash?

Je suis en train d'apprendre à utiliser la bibliothèque lodash, mais je suis tombé sur un problème que je ne pense pas pouvoir résoudre. Je veux trier un tableau imbriqué qui ressemble à ceci avec lodash:

[
    {
        "id": "54321",
        "name": "toy321",
        "date_created": "2017-08-29T16:10:37Z",
        "date_last_modified": "2019-01-29T17:19:36Z",
        "prices": [
            {
                "currency": "USD",
                "amount": "80.00"
            },
            {
                "currency": "EUR",
                "amount": "70.58"
            },
        ]
  },
  {
        "id": "12345",
        "name": "toy123",
        "date_created": "2017-08-29T16:10:37Z",
        "date_last_modified": "2019-01-29T17:19:36Z",
        "prices": [
            {
                "currency": "USD",
                "amount": "100.00"
            },
            {
                "currency": "EUR",
                "amount": "88.23"
            },
        ]
    },
]

Je veux trier le tableau en fonction du tableau prix qui est imbriqué dans le tableau donné . Le tri prendra en compte les price.currency et price.amount et produira la sortie comme ci-dessous où le tableau donné est trié par ordre croissant en fonction de USD code > et montant . Et un autre problème que j'ai est que le price.amount est une chaîne, pas un nombre.

"results": [
  {
        "id": "12345",
        "name": "toy123",
        "date_created": "2017-08-29T16:10:37Z",
        "date_last_modified": "2019-01-29T17:19:36Z",
        "prices": [
            {
                "currency": "USD",
                "amount": "100.00"
            },
            {
                "currency": "EUR",
                "amount": "88.23"
            },
        ]
    },
    {
        "id": "54321",
        "name": "toy321",
        "date_created": "2017-08-29T16:10:37Z",
        "date_last_modified": "2019-01-29T17:19:36Z",
        "prices": [
            {
                "currency": "USD",
                "amount": "80.00"
            },
            {
                "currency": "EUR",
                "amount": "70.58"
            },
        ]
    },
]

Merci d'avance pour votre gentillesse et de cours votre temps.


4 commentaires

Pouvez-vous élaborer la partie de tri. Qu'entendez-vous par tri en USD et base de montant?


price.amount n'est pas un problème car vous bénéficierez de la flexibilité du premier parseInt, puis comparez


@binariedMe cela signifie que le tableau est trié en fonction du montant avec la devise en USD.


Eh bien, d'autres ont déjà répondu selon vos besoins alors. Je pense qu'ils devraient bien fonctionner.


3 Réponses :


5
votes

La méthode _.sortBy () ne prend pas en charge comparateur personnalisé, vous devez utiliser Array .prototype.sort () à la place. Vous n'avez pas non plus besoin d'analyser price.amount , String.prototype.localeCompare () peut faire la comparaison pour vous, il prend en charge les chaînes avec des valeurs numériques.

En mettant tout cela ensemble, votre la mise en œuvre peut ressembler à ceci:

results.sort((a, b) => {
    const priceA = _.find(a.prices, { currency: 'USD' });
    const priceB = _.find(b.prices, { currency: 'USD' });
    return priceA.amount.localeCompare(priceB.amount, undefined, { numeric: true });
});


4 commentaires

Cela va construire une nouvelle fonction de comparaison pour chaque élément du tableau, regardez ma solution ci-dessous pour voir comment mettre en cache la fonction de comparaison pour de meilleures performances.


Votre solution est assez alambiquée et illisible à mon avis, c'est une façon très détournée de faire quelque chose de très simple. Votre solution effectue également une itération sur les résultats deux fois supplémentaires et crée deux nouveaux tableaux. De quelle manière fonctionne-t-il mieux? Avez-vous des repères?


Êtes-vous sûr que vous regardez ma solution?


Désolé, j'ai vu "cache" et j'ai vu l'autre réponse avec "cache". Je n'étais pas au courant de Intl.Collator merci pour le partage!



4
votes

Pas besoin de bibliothèques externes comme loadash.

const arr = [
  {
        "id": "12345",
        "name": "toy123",
        "date_created": "2017-08-29T16:10:37Z",
        "date_last_modified": "2019-01-29T17:19:36Z",
        "prices": [
            {
                "currency": "USD",
                "amount": "100.00"
            },
            {
                "currency": "EUR",
                "amount": "88.23"
            },
        ]
    },
    {
        "id": "54321",
        "name": "toy321",
        "date_created": "2017-08-29T16:10:37Z",
        "date_last_modified": "2019-01-29T17:19:36Z",
        "prices": [
            {
                "currency": "USD",
                "amount": "80.00"
            },
            {
                "currency": "EUR",
                "amount": "70.58"
            },
        ]
    },
];

const naturalSort = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }).compare;

arr.sort((a,b) => naturalSort(a.prices.find(p => p.currency === 'USD').amount, b.prices.find(p => p.currency === 'USD').amount));

console.log(arr);


2 commentaires

une raison particulière pour laquelle vous avez utilisé sensibilité: 'base' ?


Pas vraiment pour cet exemple, il vient probablement d'un copier-coller dans cet exemple. Je l'utilise toujours lorsque je crée un assembleur intl pour être insensible à la casse.



0
votes

et optimisez en mettant en cache la recherche de prix qui sera sinon effectuée plusieurs fois sur chaque article.

const results = [
  {
    "id": "12345",
    "name": "toy123",
    "date_created": "2017-08-29T16:10:37Z",
    "date_last_modified": "2019-01-29T17:19:36Z",
    "prices": [
      { "currency": "USD", "amount": "100.00" },
      { "currency": "EUR", "amount": "88.23" },
    ]
  },
  {
    "id": "54321",
    "name": "toy321",
    "date_created": "2017-08-29T16:10:37Z",
    "date_last_modified": "2019-01-29T17:19:36Z",
    "prices": [
      { "currency": "USD", "amount": "80.00" },
      { "currency": "EUR", "amount": "70.58" },
    ]
  },
];

function sortResults(results, curr) {
  return results
    .map(result => ([result, result.prices.find(price => price.currency === curr).amount - 0]))
    .sort((a, b) => a[1] - b[1])
    .map(res => res[0]);
}

console.log(sortResults(results, "USD").map(res => res.name));


0 commentaires