#javascript #arrays #lodash
#javascript #массивы #Lodash
Вопрос:
У меня есть два массива объектов. Моя цель — заменить объект из второго массива на первый на основе «id». У меня есть рабочее решение, но я хотел бы расширить его, добавив объект в первый массив, если значение не найдено. Пожалуйста, посоветуйте.
function mergeById(arr) {
return {
with: function(arr2) {
return _.map(arr, item => {
return _.find(arr2, obj => obj.id === item.id) || item
})
}
}
}
var result = mergeById([{
id: '124',
name: 'qqq'
},
{
id: '589',
name: 'www'
},
{
id: '567',
name: 'rrr'
}
])
.with([{
id: '124',
name: 'ttt'
}, {
id: '45',
name: 'yyy'
}])
console.log(result);
/**
[
{
"id": "124",
"name": "ttt"
},
{
"id": "589",
"name": "www"
},
{
"id": "567",
"name": "rrr"
},
{
id: '45',
name: 'yyy'
}
]
**/
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.20/lodash.min.js"></script>
Пожалуйста, посоветуйте.
Ответ №1:
Вам нужно отфильтровать второй массив и добавить значения, у которых нет общего идентификатора.
function mergeById(arr) {
return {
with: function(arr2) {
return [
..._.map(arr, item => _.find(arr2, obj => obj.id === item.id) || item),
..._.filter(arr2, item => !_.some(arr, obj => obj.id === item.id))
];
}
}
}
var result = mergeById([{ id: '124', name: 'qqq' }, { id: '589', name: 'www' }, { id: '567', name: 'rrr' } ])
.with([{ id: '124', name: 'ttt' }, { id: '45', name: 'yyy' }]);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.20/lodash.min.js"></script>
Более короткий подход с Map
одиночными циклами и для каждого массива.
function mergeById(array) {
const
add2map = (m, o) => m.set(o.id, o),
map = array.reduce(add2map, new Map);
return {
with: function(array2) {
return Array.from(array2
.reduce(add2map, map)
.values()
);
}
}
}
var result = mergeById([{ id: '124', name: 'qqq' }, { id: '589', name: 'www' }, { id: '567', name: 'rrr' } ])
.with([{ id: '124', name: 'ttt' }, { id: '45', name: 'yyy' }]);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Комментарии:
1. Спасибо, как всегда 🙂
Ответ №2:
Используется _.differenceBy(arr2, arr, 'id')
для поиска всех элементов, которые появляются в arr2
, которые не имеют аналога в arr
by id
, и связывают их с результатами _.map()
действия.
Примечание: вместо того, чтобы использовать _.find()
(O(n)) на каждой итерации, выполните итерацию arr2
один раз с _.keyBy()
помощью (O(n)) для создания словаря { [id]: item }
, а затем получите элементы в O(1) .
const mergeById = arr => ({
with(arr2) {
const arr2Dict = _.keyBy(arr2, 'id')
return _.map(arr, item => arr2Dict[item.id] || item)
.concat(_.differenceBy(arr2, arr, 'id'))
}
})
const result = mergeById([{ id: '124', name: 'qqq' }, { id: '589', name: 'www' }, { id: '567', name: 'rrr' } ])
.with([{ id: '124', name: 'ttt' }, { id: '45', name: 'yyy' }])
console.log(result)
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.20/lodash.min.js"></script>
Вы можете заменить / добавить в одном цикле, объединив оба массива, сведя их к карте и просто добавив элементы id
на карту:
const mergeById = arr => ({
with(arr2) {
return Array.from(
[...arr, ...arr2]
.reduce((r, o) => r.set(o.id, o), new Map)
.values()
)
}
})
const result = mergeById([{ id: '124', name: 'qqq' }, { id: '589', name: 'www' }, { id: '567', name: 'rrr' } ])
.with([{ id: '124', name: 'ttt' }, { id: '45', name: 'yyy' }])
console.log(result)
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.20/lodash.min.js"></script>
Комментарии:
1. Почему два ? ?
2. будьте более конкретными
3. Извините, в вашем коде было два вопросительных знака. Похоже, вы отредактировали его сейчас. Спасибо
4. 2 вопросительных знака
??
называются нулевым объединяющим оператором , но для этого ответа они не нужны, и я подумал, что они могут сбивать с толку, поэтому я их отредактировал.