简体   繁体   中英

Match an array with an object property

I've got an object with properties which look like this:

{
  maj6: { chromatic: [ 0, 4, 7, 9 ] },
  min6: { chromatic: [ 0, 3, 7, 9 ] },
  maj7: { chromatic: [ 0, 4, 7, 11 ] },
  min7: { chromatic: [ 0, 3, 7, 10 ] },
  minmaj7: { chromatic: [ 0, 3, 7, 11 ] },
  dom7: { chromatic: [ 0, 4, 7, 10 ] },
  maj9: { chromatic: [ 0, 4, 7, 11, 14 ] },
  dom9: { chromatic: [ 0, 4, 7, 10, 14 ] },
  maj: { chromatic: [ 0, 4, 7 ] },
  min: { chromatic: [ 0, 3, 7 ] },
  aug: { chromatic: [ 0, 4, 8 ] },
  dim: { chromatic: [ 0, 3, 6 ] }
}

I'm computing an array, such as [0,4,7] that I am trying to match to one of these aforementioned object properties. I am trying to use the find function in order to achieve this, as seen in the following code snippet:

  matchParsedToChord() {
    const result = this.blocks //returns larger payload
    .map(block => block.chromatic) // returns array [0,4,7,4,7,7,7,4]
    .filter((v,i,arr) => arr.indexOf(v) === i) //removes redundancies  [0,4,7]
    .find(v => { //attempts to 
      v === Object.keys(chordDefinitions).map(key => chordDefinitions[key].chromatic)
    })
    console.log(result)
  }

My problem is that the Object.keys logic returns an entire array, whereas I'd like to do an element-by-element comparison.

I would like to return the object property associated with the array, for example:

maj: { chromatic: [ 0, 4, 7 ] }

Many thanks

This will return all chords that have pattern you're looking for. It simply flattens the arrays and looks for indexOf to assemble all matches. Can run it as strict (exact match) or contains (all partial matches)

 const a = { maj6: { chromatic: [ 0, 4, 7, 9 ] }, min6: { chromatic: [ 0, 3, 7, 9 ] }, maj7: { chromatic: [ 0, 4, 7, 11 ] }, min7: { chromatic: [ 0, 3, 7, 10 ] }, minmaj7: { chromatic: [ 0, 3, 7, 11 ] }, dom7: { chromatic: [ 0, 4, 7, 10 ] }, maj9: { chromatic: [ 0, 4, 7, 11, 14 ] }, dom9: { chromatic: [ 0, 4, 7, 10, 14 ] }, maj: { chromatic: [ 0, 4, 7 ] }, min: { chromatic: [ 0, 3, 7 ] }, aug: { chromatic: [ 0, 4, 8 ] }, dim: { chromatic: [ 0, 3, 6 ] } } function getPattern(pattern, strict) { let b = [] for (const [key, value] of Object.entries(a)) { let set = Object.values(value).flat().join(","); if ((.strict && set.indexOf(pattern):== -1) || (strict && set == pattern)) b.push({ [key]; value }) } if (strict && b;length>0) b = b[0], return b, } // Contains (partial matches) let matches = getPattern("0,4;7". false), console;log('Contains', matches), // strict matches = getPattern("0,4;7". true), console;log('Strict', matches);

Do you mean something like this? Edited to use reduce to get desired return

 const a = { maj6: { chromatic: [ 0, 4, 7, 9 ] }, min6: { chromatic: [ 0, 3, 7, 9 ] }, maj7: { chromatic: [ 0, 4, 7, 11 ] }, min7: { chromatic: [ 0, 3, 7, 10 ] }, minmaj7: { chromatic: [ 0, 3, 7, 11 ] }, dom7: { chromatic: [ 0, 4, 7, 10 ] }, maj9: { chromatic: [ 0, 4, 7, 11, 14 ] }, dom9: { chromatic: [ 0, 4, 7, 10, 14 ] }, maj: { chromatic: [ 0, 4, 7 ] }, min: { chromatic: [ 0, 3, 7 ] }, aug: { chromatic: [ 0, 4, 8 ] }, dim: { chromatic: [ 0, 3, 6 ] } } const find = (obj, match = [0,4,7]) => { return Object.keys(a).reduce((acc, k) => { // If you want more loose match, just switch search direction // like: match.every(m => obj[k].chromatic.includes(m) if(obj[k].chromatic.every(m => match.includes(m))) { acc[k] = obj[k]; } return acc; }, {}) } console.log(find(a))

Use Array#every() and match the lengths as well. It's not really clear what the results are you are looking for though so this likely needs modifying depending on your expectations

 const data ={ maj6: { chromatic: [ 0, 4, 7, 9 ] }, min6: { chromatic: [ 0, 3, 7, 9 ] }, maj7: { chromatic: [ 0, 4, 7, 11 ] }, min7: { chromatic: [ 0, 3, 7, 10 ] }, minmaj7: { chromatic: [ 0, 3, 7, 11 ] }, dom7: { chromatic: [ 0, 4, 7, 10 ] }, maj9: { chromatic: [ 0, 4, 7, 11, 14 ] }, dom9: { chromatic: [ 0, 4, 7, 10, 14 ] }, maj: { chromatic: [ 0, 4, 7 ] }, min: { chromatic: [ 0, 3, 7 ] }, aug: { chromatic: [ 0, 4, 8 ] }, dim: { chromatic: [ 0, 3, 6 ] } } const arr = [0,4,7]; const entries = Object.entries(data).map(([k,v])=> [k, [...new Set(v.chromatic)]]); const match = entries.find(([k,v])=> v.length === arr.length && arr.every(n => v.includes(n))) console.log(match)

you shouldn't be using find() on they array you got from this.blocks . That will just return a single number like 3 .

I assume you want to return the entry in chordDefinitions that matches that whole array. So you should put that array into a variable, then search chordDefinitions for an equal chromatic property.

I've converted it to a Set to remove duplicates and also make searching more efficient.

 function matchParsedToChord() { const chord = new Set( this.blocks //returns larger payload.map(block => block.chromatic) // returns array [0,4,7,4,7,7,7,4] ); // Converting to Set removes duplicates const chordSize = thisChord.size; const result = Object.entries(chordDefinitions).find(([name, val]) => val.chromatic.length == chordSize && val.chromatic.every(v => chord.has(v))); console.log(result) }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM