#javascript #arrays #reactjs #filter
#javascript #массивы #reactjs #Фильтр
Вопрос:
Я хотел бы удалить элемент из массива, который находится внутри объекта, и переопределить этот объект новыми значениями. Смотрите пример ниже.
var obj = {
a: [1, 2, 3],
b: [4, 5, 6],
c: [7, 8, 9]
}
Я хотел бы удалить число 5, obj
не зная, в каком массиве находится элемент.
Я пытаюсь обновить состояние в react с помощью Context API. Он должен непосредственно возвращать сам объект.
case ACTION: return {
...state,
obj: ?
}
Ожидаемый конечный результат :
var obj = {
a: [1, 2, 3],
b: [4, 6],
c: [7, 8, 9]
}
Комментарии:
1. Вы отметили это
react
, используете ли вы это с помощью state ? Если это так, ответ будет другим, поскольку вы не хотите напрямую изменять массив.2. Да, я использую его
react
внутри контекста
Ответ №1:
Чтобы сгенерировать новый объект с обновленными значениями, вы можете использовать Object.entries()
для преобразования объекта в записи [ключ, значение] . Сопоставьте записи и отфильтруйте массив значений, а затем преобразуйте записи обратно в объект с помощью Object.fromEntries()
:
const fn = (obj, item) =>
Object.fromEntries(
Object.entries(obj)
.map(([k, v]) => [k, v.filter(o => o !== item)])
)
const obj = {
a: [1, 2, 3],
b: [4, 6],
c: [7, 8, 9]
}
const result = fn(obj, 5)
console.log(result)
Здесь есть небольшая проблема, которая может привести к ненужному отображению — поскольку мы фильтруем все массивы, каждый массив является новым, даже если элемент изначально не существует в этом массиве. Мы можем решить эту проблему, проверив, действительно ли массив содержит элемент, прежде чем фильтровать его. Это может быть преждевременной оптимизацией, и ее следует профилировать.
const fn = (obj, item) =>
Object.fromEntries(
Object.entries(obj)
.map(e => e[1].includes(item) ? [e[0], e[1].filter(o => o !== item)] : e)
)
const obj = {
a: [1, 2, 3],
b: [4, 6],
c: [7, 8, 9]
}
const result = fn(obj, 5)
console.log(result.c === obj.c) // c didn't change
console.log(result)
Если Object.fromEntries()
он не поддерживается вашей средой, вы можете легко заменить его функцией, основанной на Array.reduce()
:
const fromEntries = entries =>
entries.reduce((obj, [k, v]) => {
obj[k] = v
return obj
}, {})
const fn = (obj, item) =>
fromEntries(
Object.entries(obj)
.map(([k, v]) => [k, v.filter(o => o !== item)])
)
const obj = {
a: [1, 2, 3],
b: [4, 6],
c: [7, 8, 9]
}
const result = fn(obj, 5)
console.log(result)
Комментарии:
1. Это именно то, что я искал. Я запустил это vanilla js, но нормально ли, что в reactjs произошла ошибка
undefined is not a function near Object.fromEntries
?2.
Object.fromEntries()
поддерживается всеми новыми браузерами. Он не поддерживается IE.3. Его легко
Object.fromEntries()
заменить функцией, основанной на reduce . Я добавлю пример.
Ответ №2:
Самый простой подход, ИМХО, был бы к splice
этому массиву:
obj.b.splice(1, 1);
РЕДАКТИРОВАТЬ:
Если вы не знаете, где будет находиться элемент (согласно комментарию), вы можете просмотреть их все и отфильтровать каждый массив:
const toRemove = 5;
Object.keys(obj).forEach(k => {
obj[k] = obj[k].filter(i => i != toRemove);
});
Комментарии:
1. Как я уже сказал @plichard, это моя вина, я оговорился. Я скорее хотел удалить элемент, введенный пользователем, не зная, где находится этот элемент
2. @CustyZ01 итак, я неправильно понял их вопрос. Смотрите мой отредактированный ответ.
3. Спасибо за ваш ответ, но возвращает ли это объект? Например, могу ли я сделать это:
obj = Object.keys(obj).forEach(k => { obj[k] = obj[k].filter(i => i != toRemove); });
я пытаюсь вернуть объект для обновления состояния реакции (см. Редактирование в вопросе)4. @CustyZ01 это обновление
obj
на месте. Если вы хотите, вы можете затем вернуть его.5. Вероятно, вы могли бы сделать
obj.b.splice(obj.b.indexOf(5), 1)