У меня есть массив объектов, которые нужно отфильтровать с помощью двух меню. Каждое меню возвращает массив. Значения этих массивов будут использоваться для фильтрации массива объектов.
Я создал пример codepen здесь: https://codepen.io/jonathank2018/pen/LYeZgQG?editors=1010
Для этого примера давайте сосредоточимся только на меню «Тузы». Логика фильтрации, которую я пытаюсь сделать, следующая. сценарий 1: когда я выбираю «Услуги» в меню «Тузы», значение «valuesAces» становится [«Услуги»]. сценарий 2: Когда я выбираю «Услуги» и «Подключено» в меню «Тузы», значение «valuesAces» становится [«Услуги», «Подключено»]. Когда я фильтрую «linksArray» со значениями, возвращаемыми из «valuesAces», мне нужно, чтобы результатом был массив со всеми объектами, которые имеют в своем свойстве aces хотя бы один из элементов в «valuesAces».
для сценария 1 я ожидаю, что в результате все объекты, которые имеют свойство aces ["Services"] как уникальное значение, и ["Services", "othervalues...", "othervalues..."].
scenario1 = [ // services selected
{ "src": "WayRay", "target": "AGP", "aces": [ "Services" ], "topic": [ "Map_Localisation" ] },
{ "src": "Great_Wall", "target": "Audi", "aces": [ "Automated", " Connected", " Experience", " Services" ], "topic": [ "AP", " AVP", " Infrastructure" ] },
{ "src": "Audi", "target": "BMW", "aces": [ "Automated", " Connected", " Experience", " Services" ], "topic": [ "AP", " AVP", " Infrastructure" ] },
{ "src": "GM", "target": "Cruise", "aces": [ "Automated", " Services" ], "topic": [ "AV_Driverless" ] },
{ "src": "Honda", "target": "Cruise", "aces": [ "Automated", " Services" ], "topic": [ "Parking" ] },
{ "src": "Audi", "target": "Daimler", "aces": [ "Services", " Connected", " Experience" ], "topic": [ "AP", " AVP", " Infrastructure" ] },
{ "src": "Xiaomi", "target": "Deepmotion", "aces": [ "Automated", " Services" ], "topic": [ "ADAS_uptoL2+", " AVP" ] },
]
для сценария 2 я ожидаю, что в результате все объекты имеют свойство aces ["Services"] или ["Services", "othervalues...", "othervalues..."] или ["Connected"] или ["Службы", "Подключено","другие значения..."] или ["Подключено","другие значения..."].
let scenario2 = [ //services and connected selected
{ "src": "WayRay", "target": "AGP", "aces": [ "Services" ], "topic": [ "Map_Localisation" ] },
{ "src": "Great_Wall", "target": "Audi", "aces": [ "Automated", " Connected", " Experience", " Services" ], "topic": [ "AP", " AVP", " Infrastructure" ] },
{ "src": "Audi", "target": "BMW", "aces": [ "Automated", " Connected", " Experience", " Services" ], "topic": [ "AP", " AVP", " Infrastructure" ] },
{ "src": "Hesai", "target": "Black_Sesame", "aces": [ "Automated", " Connected" ], "topic": [ "AV_Driverless" ] },
{ "src": "GM", "target": "Cruise", "aces": [ "Automated", " Services" ], "topic": [ "AV_Driverless" ] },
{ "src": "Honda", "target": "Cruise", "aces": [ "Automated", " Services" ], "topic": [ "Parking" ] },
{ "src": "Audi", "target": "Daimler", "aces": [ "Services", " Connected", " Experience" ], "topic": [ "AP", " AVP", " Infrastructure" ] },
{ "src": "Xiaomi", "target": "Deepmotion", "aces": [ "Automated", " Services" ], "topic": [ "ADAS_uptoL2+", " AVP" ] },
{ "src": "BMW", "target": "Deutsche_Telekom", "aces": [ "Connected" ], "topic": [ "E/E_Architecture" ] },
]
Если свойство aces объекта имеет хотя бы одно или несколько значений из valuesAces, то оно должно быть в результате фильтрации.
Проблема, с которой я сейчас сталкиваюсь в своем примере кода, заключается в том, что он не фильтрует так, как я этого хочу. Прямо сейчас, если я ссылаюсь на сценарий 2, в результате я нахожу только объекты, которые имеют в качестве свойства aces либо «Services», либо «Connected» в качестве первого элемента массива, но не объекты, которые имеют несколько элементов в свойстве aces и где «Сервисы» или «Подключено» не имеют индекса 0. Похоже, что все остальные элементы в массиве игнорируются, кроме первого.
Моя функция фильтрации выглядит так:
filteredLinks: function(){
console.info("1")
let result
if (this.linksArray){
if (
(!this.valuesTopic || this.valuesTopic.length == 0) // by topic
&& (!this.valuesAces || this.valuesAces.length == 0) // by ACES
){
console.info("2")
result = this.linksArray
}else{
console.info("3")
result = this.linksArray.filter(link => { return (
( !this.valuesTopic || this.valuesTopic.length == 0 || ([...link.topic].some(topic => this.valuesTopic.includes(topic)))) // by topic
&&( !this.valuesAces || this.valuesAces.length == 0 || ([...link.aces].some(ace => this.valuesAces.includes(ace)))) // by ACES
)})
}
return result;
}
},
Вы можете отфильтровать массив linksArray
, проверив, существуют ли элементы массива linksArray.aces
в valuesAces
следующим образом:
// Filter linksArray
linksArray.filter((item) => {
return item.aces
// 'aces' values in provided codepen has spaces so trim those.
// If actual data doesn't have spaces, this map can be removed.
.map((i) => {
return i.trim()
})
// Check if 'acesValues' are in 'linksArray.aces' array
.some((v) => {
return valuesAces.includes(v)
})
})
Или как один лайнер:
linksArray.filter((item) => item.aces.map((i) => i.trim()).some((v) => acesValues.includes(v)))
Вот пример:
let linksArray = [
{ src: 'SemiDrive', target: 'ADAYO', aces: ['Automated', ' Experience'], topic: ['EE_Architecture'] },
{ src: 'WayRay', target: 'AGP', aces: ['Services'], topic: ['Map_Localisation'] },
{ src: 'Hesai', target: 'Aiways', aces: ['Automated'], topic: ['Car_Access'] },
{ src: 'Oxbotica', target: 'AppliedEV', aces: ['Automated'], topic: ['Regulation'] },
{ src: 'Great_Wall', target: 'Audi', aces: ['Automated', ' Connected', ' Experience', ' Services'], topic: ['AP', ' AVP', ' Infrastructure'] },
{ src: 'Audi', target: 'BMW', aces: ['Automated', ' Connected', ' Experience', ' Services'], topic: ['AP', ' AVP', ' Infrastructure'] },
{ src: 'AEye', target: 'Benchmark', aces: ['Automated'], topic: [] },
{ src: 'Hesai', target: 'Black_Sesame', aces: ['Automated', ' Connected'], topic: ['AV_Driverless'] },
{ src: 'FAW', target: 'Cambricon', aces: ['Automated'], topic: ['AS_ADAS_uptoL2+'] },
{ src: 'GM', target: 'Cruise', aces: ['Automated', ' Services'], topic: ['AV_Driverless'] },
{ src: 'Honda', target: 'Cruise', aces: ['Automated', ' Services'], topic: ['Parking'] },
{ src: 'Audi', target: 'Daimler', aces: ['Services', ' Connected', ' Experience'], topic: ['AP', ' AVP', ' Infrastructure'] },
{ src: 'Xiaomi', target: 'Deepmotion', aces: ['Automated', ' Services'], topic: ['ADAS_uptoL2+', ' AVP'] },
{ src: 'Alibaba', target: 'Deeproute', aces: ['Automated'], topic: ['AD_Driverless'] },
{ src: 'BMW', target: 'Deutsche_Telekom', aces: ['Connected'], topic: ['E/E_Architecture'] }
]
let acesValues1 = ['Services']
let acesValues2 = ['Services', 'Connected']
const filterLinks = (links, aces) =>
links.filter((item) => item.aces.map((i) => i.trim()).some((v) => aces.includes(v)))
console.info(filterLinks(linksArray, acesValues1))
console.info(filterLinks(linksArray, acesValues2))
РЕДАКТИРОВАТЬ
Основываясь на комментариях ОП, из значений linksArray.aces
удалены начальные пробелы и добавлен фильтр тем:
let linksArray = [
{ src: 'SemiDrive', target: 'ADAYO', aces: ['Automated', 'Experience'], topic: ['EE_Architecture'] },
{ src: 'WayRay', target: 'AGP', aces: ['Services'], topic: ['Map_Localisation'] },
{ src: 'Hesai', target: 'Aiways', aces: ['Automated'], topic: ['Car_Access'] },
{ src: 'Oxbotica', target: 'AppliedEV', aces: ['Automated'], topic: ['Regulation'] },
{ src: 'Great_Wall', target: 'Audi', aces: ['Automated', 'Connected', 'Experience', 'Services'], topic: ['AP', ' AVP', ' Infrastructure'] },
{ src: 'Audi', target: 'BMW', aces: ['Automated', 'Connected', 'Experience', 'Services'], topic: ['AP', ' AVP', ' Infrastructure'] },
{ src: 'AEye', target: 'Benchmark', aces: ['Automated'], topic: [] },
{ src: 'Hesai', target: 'Black_Sesame', aces: ['Automated', 'Connected'], topic: ['AV_Driverless'] },
{ src: 'FAW', target: 'Cambricon', aces: ['Automated'], topic: ['AS_ADAS_uptoL2+'] },
{ src: 'GM', target: 'Cruise', aces: ['Automated', 'Services'], topic: ['AV_Driverless'] },
{ src: 'Honda', target: 'Cruise', aces: ['Automated', 'Services'], topic: ['Parking'] },
{ src: 'Audi', target: 'Daimler', aces: ['Services', 'Connected', 'Experience'], topic: ['AP', ' AVP', ' Infrastructure'] },
{ src: 'Xiaomi', target: 'Deepmotion', aces: ['Automated', 'Services'], topic: ['ADAS_uptoL2+', 'AVP'] },
{ src: 'Alibaba', target: 'Deeproute', aces: ['Automated'], topic: ['AD_Driverless'] },
{ src: 'BMW', target: 'Deutsche_Telekom', aces: ['Connected'], topic: ['E/E_Architecture'] }
]
let aces = ['Services']
let topics = ['ADAS_uptoL2+']
const filterLinks = (links, aces, topics) =>
links
.filter((item) => item.aces.some((v) => (aces.length ? aces.includes(v) : v)))
.filter((item) => item.topic.some((v) => (topics.length ? topics.includes(v) : v)))
let result = filterLinks(linksArray, aces, topics)
console.info(result)
@Tim, спасибо за подробный ответ. Применительно к одному из меню он работает по назначению. Теперь я хотел бы иметь возможность применять фильтры из обоих меню. Например, если я выбрал Services в меню Aces и ADAS_uptoL2+ в меню Topic, ожидаемый результат будет следующим: [ { "src": "Xiaomi", "target": "Deepmotion", "aces": [ "Automated ", "Сервисы" ], "тема": [ "ADAS_uptoL2+", "AVP" ] } ]
До сих пор я пробовал это: До сих пор я пробовал это: const filterLinks = this.linksArray.filter((item) => { return( item.topic.some((v) => this.valuesTopic.includes(v) ) )}) const filterLinks2 = this.filterLinks.filter((item) => { return( item.aces.some((v) => this.valuesAces.includes(v)) )}) result = filterLinks2
и это: const filterLinks = this.linksArray.filter((item) => { return( item.aces.some((v) => this.valuesAces.includes(v)) && item.topic.some((v) => this.valuesTopic.includes(v)) )}) result = filterLinks Но ни одна из них не работает, я не знаю, что я делаю неправильно..
Я забыл упомянуть, что я исправил пробелы, чтобы удалить map()
@ JK2018, пожалуйста, смотрите мое редактирование выше.
@ Тим, чудесно! Работает как часы. Спасибо за качественную консультацию. Вы сделали мой день!
Более общий метод может выглядеть примерно так:
const getFiltered = (column, values=[]) => linksArray.filter(lnkObj => lnkObj[column].some(el => values.includes(el.trim());
. Теперь этот же метод можно использовать дляtopic
. Я предполагаю, что следующим будет какой-то способ объединить оба (фильтр тузов и фильтр темы). :)