2

I'm filtering some arrays of objects by keyword using the JavaScript Array Filter. Initial, I had an array of objects:

  let works = [
    { title: ' work 1', medium: 'tax1' },
    { title: ' work 2', medium: 'tax2' },
    { title: ' work 3', medium: 'tax3' },
    { title: ' work 4', medium: 'tax2' },
    { title: ' work 5', medium: 'tax1' }
  ]

And could filter the array by the 'medium' in this manner:

    mediumFilter(taxonomy) {
        return works.filter(item => {
            return (
              item.medium.indexOf(taxonomy) > -1
            );
        });
    },

When I pass the taxonomy variable to the mediumFilter(), in this case 'tax1' or so -- I get an array that includes the items containing that specific medium.

This was initial -- now that my project is getting more complex, I find myself struggling. My new array includes a nested array, which are the values to match in the filtering.

  let works = [
    { title: ' work 1', medium: [ 'tax1', 'tax3' ] },
    { title: ' work 2', medium: [ 'tax1' ] },
    { title: ' work 3', medium: [ 'tax3' ] },
    { title: ' work 4', medium: [ 'tax2', 'tax1' ] },
    { title: ' work 5', medium: [ 'tax1' ] }
  ]

Notice how the medium is an array holding multiple strings.

I'm looking for some assistance on how to approach this. I need my function to return items that match the variable im passing. As some works could have multiple mediums, I need to be able to filter by multiple values. If the array of mediums has multiple values, only one needs to match.

Thanks!

btw im using vue which is not relevant to the question but syntax of my examples might not be exact.

2
  • 1
    what should be the result for this mediumFilter(['tax3','tax2']) ? Commented Jul 15, 2017 at 18:38
  • Hi -- User can only filter by one category at this stage, so the variable to pass into the function will always be a single string! Still this is very important to consider Commented Jul 15, 2017 at 18:48

6 Answers 6

2

You could use Array#includes and check the string.

let works = [{ title: 'work 1', medium: ['tax1', 'tax3'] }, { title: 'work 2', medium: ['tax1'] }, { title: 'work 3', medium: ['tax3'] }, { title: 'work 4', medium: ['tax2', 'tax1'] }, { title: 'work 5', medium: ['tax1'] }],
   mediumFilter = taxonomy => works.filter(item => item.medium.includes(taxonomy));

console.log(mediumFilter('tax3'));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Sign up to request clarification or add additional context in comments.

1 Comment

This is exactly what I was looking for :~)!! Thank you so much
1

If I got your question right then this should work:

function mediumFilter(taxonomy) {
    return works.filter(x => x.medium.indexOf(taxonomy) > -1 );
}

1 Comment

Thanks! Actually this was my initial approach -- it works if the Array works property medium is a single string. Since my medium now is an array, some nested logic is needed to check multiple matches
0
mediumFilter(taxonomy) {
    return works.forEach(item => {
        for(let i = 0; i < item.medium.length; i++){
            if(item.medium[i].indexOf(taxonomy) > -1){
                return true;
            }
        }
        return false;
    });
},

I believe this is what you had in mind. If taxonomy is an array (and always will be, no doing mediumFilter('tax1') and mediumFilter(['tax1','tax2']) then you can do this as well:

mediumFilter(taxonomy) {
    return works.forEach(item => {
        for(let i = 0; i < item.medium.length; i++){
            for(elem of taxonomy){
                if(item.medium[i].indexOf(elem) > -1){
                     return true;
                }
            }
        }
        return false;
    });
},

1 Comment

Thank you! This approach helps me understand the logic needed to achieve what I want! In my case I was expecting it to return a new array -- instead of a boolean. I updated my question!
0

You could modify the function to accept arrays in both the object and the search query

function mediumFilter(taxonomy) {
    taxonomy = Array.isArray(taxonomy) ? taxonomy : [taxonomy];
    return works.filter(item => {
        let medium = Array.isArray(item.medium) ? item.medium : [item.medium];
        return taxonomy.some(med => medium.includes(med));
    });
}

let works = [
  {title: ' work 1', medium: ['tax1', 'tax2']}, 
  {title: ' work 2', medium: 'tax2'}, 
  {title: ' work 3', medium: 'tax3'}, 
  {title: ' work 4', medium: 'tax4'}, 
  {title: ' work 5', medium: 'tax5'}
];

function log(x) {console.log( x.map( y => y.title) )}

log( mediumFilter('tax1') );           // 1
log( mediumFilter(['tax1', 'tax2']) ); // 1, 2
log( mediumFilter('tax2') );           // 1, 2
log( mediumFilter(['tax4']) );         // 4

Comments

0

let works = [
  { title: ' work 1', medium: [ 'tax1', 'tax3' ] },
  { title: ' work 2', medium: [ 'tax1' ] },
  { title: ' work 3', medium: [ 'tax3' ] },
  { title: ' work 4', medium: [ 'tax2', 'tax1' ] },
  { title: ' work 5', medium: [ 'tax1' ] }
]

  function mediumFilter(taxonomy) {
      return works.filter(item => {
          return item.medium.filter(subitem => {
              return (
                  subitem.indexOf(taxonomy) > -1
              );
          });
      });
  }

  console.log(mediumFilter('tax1'));

Comments

0

You should avoid nested loops. I would change the data structure, to accommodate a more efficient search.{tax1:['work 1','work 2'], tax2:[],}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.