3

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.

4
  • Can you elaborate the sorting part. What do you mean by sorting on USD and amount base? Commented Mar 5, 2019 at 3:08
  • price.amount is not an issue because you'd get the flexibility of first parseInt and then compare Commented Mar 5, 2019 at 3:08
  • @binariedMe it means the array is sorted based on the amount with the currency in USD. Commented Mar 5, 2019 at 3:41
  • Well, others have already answered as per your requirement then. I think they should work fine. Commented Mar 5, 2019 at 3:42

3 Answers 3

6

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 });
});
Sign up to request clarification or add additional context in comments.

3 Comments

This is going to construct a new comparison function for every item in the array, look at my solution below to see how to cache the comparison function for better performance.
Sure you are looking at my solution?
Sorry, I saw "cache" and saw the other answer with "cache". I wasn't aware of Intl.Collator thanks for sharing!
4

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

2 Comments

any particular reason you used sensitivity: 'base' ?
Not really for this example, it probably come from a copy and paste in this example. I always use it when I create an intl collator to be case insensitive.
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.