'Filtering property of type array on an array of objects by using another array

I have an array of objects that needs to be filtered by using two menus. Each menu returns an array. The values of these arrays will be used to filter the object array.

I have created a codepen example here : https://codepen.io/jonathank2018/pen/LYeZgQG?editors=1010

For this example lets concentrate on the "Aces" menu only. The filtering logic that i am trying to make is the following. scenario 1 : When I select "Services" from the "Aces" menu, the value of "valuesAces" becomes ["Services"]. scenario 2 : When I select "Services" and "Connected" from the "Aces" menu, the value of "valuesAces" becomes ["Services","Connected"]. When I filter "linksArray" with the values returned from "valuesAces", I need the result to be an array with all the objects that have within their aces property at least one of the items in "valuesAces".

for scenario 1 , I expect as result all the objects that have as their aces property ["Services"] as unique value, and ["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" ] },
                     ]

for scenario 2 , I expect as result all the objects that have as their aces property ["Services"] , or ["Services", "othervalues...","othervalues..."], or ["Connected"], or ["Services", "Connected","othervalues..."], or ["Connected","othervalues..."].

 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" ] },  
                      ]

If the object's aces property has at least one or several values from valuesAces, then it needs to be in the result of the filter.

The problem I am currently facing with my codepen example, is that it is not filtering the way I want it to. Right now if i refer to scenario 2, in the result I only find the objects that have as aces property either "Services" or "Connected" as first item of the array , but not the objects that have several items in the aces property and where "Services" or "Connected" are not at index 0. It seems to ignore all other items in the array exept for the first one.

My filtering function looks like this :

filteredLinks: function(){
      console.log("1")
          let result
          if(this.linksArray){
          if(
            (!this.valuesTopic || this.valuesTopic.length == 0)  // by topic
            && (!this.valuesAces || this.valuesAces.length == 0)  // by ACES
             ){
            console.log("2")
                result  = this.linksArray
          }else{
            console.log("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;
          }
      },


Solution 1:[1]

You could filter the linksArray array based on checking if linksArray.aces array items exist in valuesAces as follows:

// 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)
    })
})

Or as a one liner:

linksArray.filter((item) => item.aces.map((i) => i.trim()).some((v) => acesValues.includes(v)))

Here is an example:

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.log(filterLinks(linksArray, acesValues1))
console.log(filterLinks(linksArray, acesValues2))

EDIT

Based on OP's comments, removed leading spaces from linksArray.aces values and added the topics filter:

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.log(result)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1