Использование Lodash для получения значения по его ключу, в то время как некоторые ключи не существуют

#javascript #arrays #lodash

Вопрос:

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

Вот как выглядит мой нефильтрованный массив, я хочу извлечь идентификатор и имя [x].текст в массив. Но, как вы можете видеть, в некоторых объектах нет французского текста, в этом случае я хочу вместо этого использовать текст на английском языке.

 const response = {
    "data": {
      "Animals": [
        {
          "id": "1",
          "name": [
            {
              "language": "en-US",
              "text": "Horse"
            }
          ]
        },
        {
          "id": "2",
          "name": [
            {
              "language": "en-US",
              "text": "Pig"
            }
          ]
        },
       {
          "id": "3",
          "name": [
            {
              "language": "en-US",
              "text": "Cat"
            },
            {
              "language": "fr-CA",
              "text": "Un Chat"
            }
          ]
        },
        {
          "id": "4",
          "name": [
            {
              "language": "en-US",
              "text": "Dog"
            },
            {
              "language": "fr-CA",
              "text": "Un Chien"
            }
          ]
        }
      ]
    }
  }


console.log(response.data.Animals.map(animal => animal.name[0].text)); // If I do this I get all the English text, but If I map the same with index of the French, I get undefined error and It crashed my application.
 

Это более подходит, поскольку возвращает текст на французском и английском языках, но я хочу внести два улучшения,

  1. Получите значение из его ключа («en-US» и «fr-CA»), чтобы я точно знал, что у меня правильное значение.
  2. Я сопоставляю для заполнения таблицы, поэтому мне не нужен новый массив со значениями, потому что я не хочу терять индекс, если родительский массив, если текст недоступен, должен найти текст на английском языке.
  3. Это дополнительный вопрос, но он поможет мне научиться лучше использовать Lodash, если я хочу установить значение (либо в En, либо в Fr), как мне это сделать?
      arr.map((obj) => {
     const id = obj.id;
     const englishtext = _.get(obj, 'name[0].text', 'N/A');
     const frenchtext = _.get(obj, 'name[1].text', englishtext);
     return { id, englishtext, frenchtext };
     

    }

ОБНОВЛЕНИЕ: прошу прощения, мой вопрос был неясным, честно говоря, я тоже немного смущен. Итак, вот ожидаемый результат, который я ищу. Поэтому, когда я сопоставляю заданный переменный ответ, мне нужен другой массив, который выглядит следующим образом,

ОЖИДАЕМЫЙ РЕЗУЛЬТАТ:

 [
{
id: 1,
engname: Horse,
frenchname: Horse (because french is not available),
},
.
.
.
{
id:3,
engname:Cat,
frenchname: Un Chat, (because the French array is there this time)
}
.
.
.
and so on.. 
] 
 

Ответ №1:

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

Если я правильно понял ваш вопрос, набор правил, который вы хотите использовать для извлечения значений, выглядит следующим образом:

  1. Если есть текст на французском языке, используйте его независимо от наличия текста на английском языке. Кроме того, французский текст всегда идет после английского текста в массиве (французский текст всегда имеет индекс -1).
  2. Если нет текста на французском языке, используйте текст на английском языке (английский текст гарантированно присутствует для всех элементов).

В этом случае, я думаю, вы могли бы использовать либо Array.prototype.pop() или Array.prototype.at() для достижения того, чего вы хотите.

Решение Array.prototype.pop()

 response.data.Animals.map(animal => animal.name.pop().text)
 

Плюсы:

  • Широко доступно во всех современных браузерах.

Минусы:

  • Это изменяет исходные данные и изменяет длину исходного массива.

Array.prototype.at () решение

 response.data.Animals.map(animal => animal.name.at(-1).text)
 

Плюсы:

  • Эта операция неизменяема, поэтому исходные данные не повреждены.

Минусы:

  • Некоторые браузеры могут не поддерживать это.

Если вы открыты для решений, отличных от Lodash, я полагаю, вы могли бы использовать одно из них.

Обновить

Спасибо @WildThing за обновление вопроса. Я думаю, вы можете использовать это для достижения желаемого сопоставления:

 response.data.Animals.map(animal => {
  engName = animal.name.find(name => name.language === "en-US");
  frenchNameIfExists = animal.name.find(name => name.language === "fr-CA");

  return {
    id: animal.id,
    engname: engName.text,
    frenchname: (frenchNameIfExists || engName).text,
  }
})

 

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

1. @WildThing Привет, я думал, ты хочешь получить либо французский, либо английский, а не оба. Можете ли вы также опубликовать структуру данных, которую вы хотите получить после сопоставления? Это может помочь мне лучше понять 🙂

2. Это потрясающе и работает, спасибо!! Я подумал, является ли это эффективным циклом? Мое приложение вернет почти 700 объектов, и использование find — хорошая идея здесь?

3. Это хороший вопрос. Я предполагаю, что массив должен быть пройден для выполнения find операции, поэтому временная сложность будет O (n) для find операции. Вам также необходимо выполнить итерацию по массиву Animals, так что в общей сложности временная сложность, вероятно, будет O (n ** 2)? Не уверен, что Lodash может предложить более быстрое решение, но определенно стоит изучить. Также было бы полезно выполнить сравнительный анализ вашего реалистичного набора данных 🙂

4. Если в animals массиве есть n элементы, а в самом большом внутреннем name массиве есть k элементы, то это решение было бы O(nk) , это не обязательно O(n^2) . Для меня даже похоже, что внутренний массив имен может иметь постоянный размер 2, что делает это O(n)

5. @NickParsons Спасибо за ваш вклад! Это настолько верно, что внутренний массив имен может иметь постоянный размер 2 🙂

Ответ №2:

Может быть, нет необходимости в lodash:

 const toMyArray = (arr, frenchnameCode = "fr-CA", engnameCode = "en-US") => {
  return arr.map(({ id, name }) => {
    const engname = name
      .find(({ language }) => language === engnameCode)
      .text;
    const frenchname =  name
      .find(({ language }) => language === frenchnameCode)
      ?.text;
      
    return { id, engname, frenchname: frenchname ?? engname }
  });
};

console.log(toMyArray(response.data.Animals));

// [
//   {id: '1', engname: 'Horse', frenchname: 'Horse'},
//   {id: '2', engname: 'Pig', frenchname: 'Pig'},
//   {id: '3', engname: 'Cat', frenchname: 'Un Chat'},
//   {id: '4', engname: 'Dog', frenchname: 'Un Chien'},
// ]