#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.
Это более подходит, поскольку возвращает текст на французском и английском языках, но я хочу внести два улучшения,
- Получите значение из его ключа («en-US» и «fr-CA»), чтобы я точно знал, что у меня правильное значение.
- Я сопоставляю для заполнения таблицы, поэтому мне не нужен новый массив со значениями, потому что я не хочу терять индекс, если родительский массив, если текст недоступен, должен найти текст на английском языке.
- Это дополнительный вопрос, но он поможет мне научиться лучше использовать 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).
- Если нет текста на французском языке, используйте текст на английском языке (английский текст гарантированно присутствует для всех элементов).
В этом случае, я думаю, вы могли бы использовать либо 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'},
// ]