Как отсортировать вложенный массив на основе значения с помощью Lodash?

#javascript #arrays #sorting #filter #lodash

#javascript #массивы #сортировка #Фильтр #Lodash

Вопрос:

Я нахожусь в процессе изучения того, как использовать библиотеку Lodash, но я столкнулся с проблемой, которую, как мне кажется, я не знаю, как решить. Я хочу отсортировать вложенный массив, который выглядит следующим образом, с помощью 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"
            },
        ]
    },
]
  

Я хочу отсортировать массив на основе prices массива, который вложен в данный массив. Сортировка будет учитывать prices.currency и prices.amount и выдаст результат, как показано ниже, где данный массив сортируется по возрастанию на основе USD и amount . И еще одна проблема, с которой я сталкиваюсь, заключается в том, что prices.amount это строка, а не число.

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

Заранее большое спасибо за вашу доброту и, конечно, за ваше время.

Комментарии:

1. Можете ли вы уточнить часть сортировки. Что вы подразумеваете под сортировкой по долларам США и базовой сумме?

2. price.amount — это не проблема, потому что вы получите гибкость первого parseInt, а затем сравните

3. @binariedMe это означает, что массив сортируется на основе суммы в валюте в долларах США.

4. Ну, тогда другие уже ответили в соответствии с вашим требованием. Я думаю, они должны работать нормально.

Ответ №1:

_.sortBy() Метод не поддерживает пользовательский компаратор, вы должны использовать Array.prototype.sort() вместо этого. Вам prices.amount также не нужно разбирать, String.prototype.localeCompare() я могу выполнить сравнение за вас, он поддерживает строки с числовыми значениями.

Собрав все это вместе, ваша реализация может выглядеть примерно так:

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

Комментарии:

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

2. Вы уверены, что смотрите на мое решение?

3. Извините, я увидел «cache» и увидел другой ответ с «cache». Я не знал о Intl.Collator спасибо, что поделились!

Ответ №2:

Нет необходимости во внешних библиотеках, таких как 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);  

Комментарии:

1. какую-либо конкретную причину вы использовали sensitivity: 'base' ?

2. На самом деле не для этого примера, это, вероятно, взято из копирования и вставки в этом примере. Я всегда использую его при создании intl collator, чтобы он не учитывал регистр.

Ответ №3:

и оптимизировать путем кэширования поиска цен, который в противном случае будет выполняться для каждого элемента несколько раз..

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