vizFlux
vizFlux

Reputation: 735

How to sort a nested array based on value with lodash?

I'm in the midst of learning how to use the lodash library, but I've bumped into a problem that I don' think I know how to solve. I want to sort a nested array that looks like this with lodash:

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

I want to sort the array based on the prices array that is nested in the given array. The sorting will take consideration of the prices.currency and prices.amount and produce the output as below where the given array is sorted ascendingly based on USD and amount. And another problem I have is that the prices.amount is a string, not a number.

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

Many thanks in advance for your kindness and of course your time.

Upvotes: 3

Views: 603

Answers (3)

Jake Holzinger
Jake Holzinger

Reputation: 6063

The _.sortBy() method does not support a custom comparator, you should use Array.prototype.sort() instead. You don't need to parse prices.amount either, String.prototype.localeCompare() can do the comparison for you, it supports strings with numeric values.

Putting it all together, your implementation might look something like this:

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

Upvotes: 6

lecstor
lecstor

Reputation: 5707

and optimise by caching the price lookup which will otherwise be performed on each item multiple times..

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

Upvotes: 0

Adrian Brand
Adrian Brand

Reputation: 21638

No need for external libraries like 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);

Upvotes: 4

Related Questions