16

I have a object containing the following:

assets = [
  { id: 1, type: 'image', url: 'image.jpg' },
  { id: 2, type: 'video', url: 'video.mp4' },
]

I'd like to filter based on user selection of IMAGE, VIDEO, or ALL.

I cannot think of a clean way to filter use for the ALL case.

currentOption = 'image'
assets.filter(asset => asset.type === currentOption)

This will work for IMAGE or VIDEO, but not ALL.

I could check in my filter function:

const currentOption = 'all'
const filterFunc = asset => {
  if (currentOption == 'all') return true
  return asset.type === currentOption
}
assets.filter(filterFunc)

But wouldn't it be better to short-circuit the filter to not iterate each item?

Edit: To answer questions why not skip filter all together. I was trying to keep it framework agnostic. But this is rendered using react. So I would have to do something like:

<div>
{currentOption === 'all' ?
  assets.map(asset => 
   <img src={asset.url} />
  )
  :
  assets.filter(asset => asset.type === currentOption).map(asset =>
   <img src={asset.url} />
  )
}
</div>

Plus this doesn't even account for the code to display a video. Basically I was trying to reduce duplication in the view code.

6
  • yes, it would be better Commented Jun 27, 2017 at 20:19
  • 4
    Why filter if it is all?? Commented Jun 27, 2017 at 20:19
  • Yup! Just check if current option is 'all', you don't need running the filter function. Commented Jun 27, 2017 at 20:20
  • @epascarello I updated the question to answer your question. But possibly still valid point. Commented Jun 27, 2017 at 20:31
  • 1
    If you want to short circuit filter instead of simply bypassing it with a condition, you would have to create your own (recursive) filter function - not particularly DRY either. So better fall back to a conditional expression. Commented Jun 27, 2017 at 20:51

4 Answers 4

14

You could use the ternary operator to decide whether or not to apply the filter:

currentOption === 'all' ? assets : assets.filter(asset => asset.type === currentOption)

The mapping to images, that you added to the end of your question, could be written like this:

(currentOption === 'all' ? assets : assets.filter(asset => asset.type === currentOption))
    .map( asset => <img src={asset.url} /> )
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. This had occurred to me, can you see my updated answer towards the end. If you think this still is the best solution.
I added how you could deal with the mapping to images.
6

I would go with what you suggested, more or less:

assets.filter(asset => currentOption === "all" || asset.type === currentOption);

Keep in mind that filter() iterates over all of the items anyway.

Comments

0

This might work for you:

assets.map(
    filter(
        asset {
            return !currentOption ? asset : asset.type === currentOption
    }
)

You could go a step further and declare an 'all' current option if you think that would be more explicit.

Hope it helps!

Comments

-3

You can do something like this:

let currentOption = null; //or 'image', or 'video'
const new_assets = 
  assets.filter(asset => !currentOption || asset.type === currentOption)

set currentOption to null if you don't want to filter, or if set it to anything, consider to do the comparison. But as said before, filter() will iterate over the entire array. It will be more wise to check the currentOption before, if it is 'all' you can just copy the array.

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.