Я хотел бы отфильтровать массив с учетом объекта фильтра
function remove (array, filter) {
// magic
}
filter
— объект переменного размера с любым количеством ключей/значений
Он должен действовать следующим образом
const products = [
{ size: 'S', color: 'blue' },
{ size: 'L', color: 'red' },
{ size: 'S', color: 'red' },
{ size: 'L', color: 'green' },
]
// With a filter of keys/value it filters for the existing key/values
const filteredProducts1 = remove(products, { size: 'S', color: 'red' })
console.info(filteredProducts1)
/*
[
{ size: 'S', color: 'blue' },
{ size: 'L', color: 'red' },
{ size: 'L', color: 'green' },
]
*/
// With less key/value than the object array, it filters for the existing key/value
const filteredProducts2 = remove(products, { size: 'S' })
console.info(filteredProducts2)
/*
[
{ size: 'L', color: 'red' },
{ size: 'L', color: 'green' },
]
*/
// With more keys/values than the object array it discard the non-existing key/value
const filteredProducts1 = remove(products, { size: 'S', color: 'red', type: 'dress' })
console.info(filteredProducts1)
/*
[
{ size: 'S', color: 'blue' },
{ size: 'L', color: 'red' },
{ size: 'L', color: 'green' },
]
*/
Моя проблема заключается в создании динамического условия из объекта фильтра
я пытаюсь преобразовать
{ key1: value1, key2: value2, ... , keyN: valueN }
в
condition 1 && condition2 && ... & conditionN
мой плохой какой-то лучше подходит в этом случае, так как вы отфильтровываете неудовлетворительные
Кстати, как вы получаете M в результатах, когда его нет на входе
Это опечатка. Я исправил исходный пост
хорошо, я думаю, что многие уже поняли это
Вы можете определить, присутствует ли какая-либо пара ключ-значение в фильтре в каждом объекте в массиве:
function remove(array, filter) {
return array.filter((obj) => {
for (const [key, value] of Object.entries(filter)) {
if (obj[key] === value) return false;
}
return true;
});
}
const products = [
{ size: "M", color: "blue" },
{ size: "S", color: "blue" },
{ size: "L", color: "red" },
{ size: "S", color: "red" },
{ size: "L", color: "green" },
];
console.info(remove(products, { size: "S", color: "red" }));
// [ { size: "M", color: "blue" }, { size: "L", color: "green" } ]
console.info(remove(products, { size: "S" }));
// [ { size: "M", color: "blue" }, { size: "L", color: "red" }, { size: "L", color: "green" } ]
console.info(remove(products, { size: "S", color: "red", type: "dress" }));
// [ { size: "M", color: "blue" }, { size: "L", color: "green" } ]
remove(products, { size: "S", color: "red" })
следует удалить size = S AND color = blue
. Ваша функция удаляет любое условие, которое выполняется. не когда все условия соблюдены/
вы можете использовать some
, чтобы вернуть true, если хотя бы одно из условий существует и не равно фильтру.
вы даже можете использовать x[k]
вместо x.hasOwnProperty(k)
, если гарантировано, что будут ключи, указывающие на значения с ложными значениями (undefined
,null
,0
..,''
).
Также MDN рекомендует Object.hasOwn вместо Object.hasOwnProperty
, если ваша среда (браузер/узел) поддерживает это.
function remove (array, filter) {
return array.filter((x) => Object.entries(filter).some(([k,v]) => x.hasOwnProperty(k) && x[k] !== v))
}
const products = [
{ size: 'S', color: 'blue' },
{ size: 'L', color: 'red' },
{ size: 'S', color: 'red' },
{ size: 'L', color: 'green' },
]
console.info(remove(products, { size: 'S', color: 'red' }))
console.info(remove(products, { size: 'S' }))
console.info(remove(products, { size: 'S', color: 'red', type: 'dress' }))
.as-console-wrapper { max-height: 100% !important; top: 0; }
редактировать решить проблему
remove(products, { type: 'dress' }) удаляет все, что не должно
теперь я отфильтровываю поля из записей фильтра, которые существуют в объекте, чтобы проверить и вернуть весь массив, если записи фильтра пусты
function remove (array, filter) {
return array.filter((x,i) => {
const entries = Object.entries(filter).filter(([k,_]) => x.hasOwnProperty(k))
if (entries.length === 0) return array
return entries.some(([k,v]) => x[k] !== v)
})
}
const products = [
{ size: 'S', color: 'blue' },
{ size: 'L', color: 'red' },
{ size: 'S', color: 'red' },
{ size: 'L', color: 'green' },
]
console.info(remove(products, { size: 'S', color: 'red' }))
console.info(remove(products, { size: 'S' }))
console.info(remove(products, { size: 'S', color: 'red', type: 'dress' }))
console.info(remove(products, { type: 'dress' }))
console.info(remove(products, {}))
.as-console-wrapper { max-height: 100% !important; top: 0; }
remove(products, { type: 'dress' })
удаляет все, что не должно
@eakl можешь проверить еще раз. я не уверен, пропустил ли я какие-либо другие крайние случаи
Кажется, это работает нормально. даже если значение равно null или undefined
@eakl, надеюсь, теперь у тебя есть идея, что изменить, когда что-то не работает.
Как насчет этого, фильтры переменных будут возвращать массив логических значений соответствующего фильтра [true, false, true] и т. д. Затем просто верните элемент обратного массива, если он включен в переменную фильтров false
const products = [
{ id: 1, size: 'S', color: 'blue', type: 'dress' },
{ id: 2, size: 'L', color: 'red', type: 'dress' },
{ id: 3, size: 'S', color: 'red', type: 'dress' },
{ id: 4, size: 'L', color: 'green', type: 'shirt' },
]
const filter1 = { size: 'S', color: 'red' }
const filter2 = { size: 'S' }
const filter3 = { size: 'S', color: 'red', type: 'dress' }
const remove = (products, filter) => {
return products.filter(product => {
const filters = Object.keys(filter).map(prop => {
return filter[prop] === product[prop]
})
return filters.includes(false)
})
}
const result1 = remove(products, filter1)
const result2 = remove(products, filter2)
const result3 = remove(products, filter3)
console.info(result1)
console.info(result2)
console.info(result3)
В remove(products, { size: 'S', color: 'red', type: 'dress' })
type = dress
следует игнорировать, так как ключ не существует. Но размер и цвет должны работать. В вашем коде type = dress
изменяет предыдущее поведение размера и цвета. remove(products, { type: 'dress' })
не должен ничего фильтровать
Я думаю, что вы правы, ключом к решению вашей проблемы является правильная реализация функции, которая может решить, следует ли удалить или сохранить элемент на основе переданных значений ключа, и которая должна иметь возможность динамически обрабатывать ваши требования.
Вот одно предложение по этому поводу:
const shouldkeep = kvs => obj => {
for (const k in kvs)
if (k in obj && obj[k] !== kvs[k])
return true
return false
}
const remove = (array, filter) => array.filter(shouldkeep(filter))
const products = [
{ size: 'S', color: 'blue' },
{ size: 'L', color: 'red' },
{ size: 'S', color: 'red' },
{ size: 'L', color: 'green' },
]
console.info(remove(products, { size: 'S', color: 'red' }))
console.info(remove(products, { size: 'S' }))
console.info(remove(products, { size: 'S', color: 'red', type: 'dress' }))
Несколько замечаний по поводу этой реализации:
shouldkeep
заключается в том, что она перебирает ключи вашего объекта фильтра и возвращает true (что означает «сохранять») только в том случае, если она проходит через все ключи без полностью совпадающих значений.shouldkeep = kvs => obj =>
может показаться странным, но на самом деле он очень полезен. Это называется каррированием и означает, что вы можете применить к функции один аргумент и получить функцию, которая ожидает следующий аргумент. При этом вы можете сделать что-то вроде products, {size: 'S'})
, и он вернет функцию, которую вы можете использовать в качестве параметра для filter
. Аккуратный!remove(products, { type: 'dress' }) удаляет все, что не должно
подсказка: массив.каждый