Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

An expression to check if an array contains a given value #4698

Closed
dagjomar opened this issue May 10, 2017 · 20 comments · Fixed by #8876
Closed

An expression to check if an array contains a given value #4698

dagjomar opened this issue May 10, 2017 · 20 comments · Fixed by #8876

Comments

@dagjomar
Copy link
Contributor

Example:
A feature has properties:

{ colors: ['red', 'green', 'blue'  }

now, I want to filter the features that has one or more of the colors I want to filter on.

filter: ['any', ['inArray', 'colors', 'green'], ['inArray', 'colors', 'blue'] ]

or

filter: [ '!inArray', 'colors', 'green' ]

It seems like the inverse variant of the membership filter 'in' and '!in'

@stevage
Copy link
Contributor

stevage commented May 11, 2017

Yes, I have run into this need as well. The use case was a map of events, where each event had several categories. I would like to do:

{ categories: ['Arts','Money','Sport'] }

and

filter: ['inArray', 'categories','Sport']

The workaround in my case was to split all the categories out:

sportCategory:true, artCategory: true, moneyCategory: true

I think that workaround is probably always possible, although it would get cumbersome for large sets.

@dagjomar
Copy link
Contributor Author

Yeah, for my use case, it will be an evergrowing large set of IDs. For example:
{ categories: [32,44,53,66,235,434] }

So filtering on boolean values is not an option :/

@kkaefer
Copy link
Member

kkaefer commented May 23, 2017

This could be subsumed by #4715

@anandthakker
Copy link
Contributor

#4715 will help with one aspect of this, but actually I think the more challenging issue is that the vector tile specification does not support arrays or objects as feature property values. (See #2434, mapbox/vector-tile-spec#75)

@dagjomar
Copy link
Contributor Author

Oh, doesn't support arrays or objects, that's a kinky thing to work around :/

Ok, how about a function to match a concated string using regex? :p

So, in my case (#4698 (comment))
Instead of the array
{ categories: [32,44,53,66,235,434] }
it would be:
{ categoriesStr: '|32|44|53|66|235|434|' }

and filter:

filter: ['regex', 'categoriesStr', /\|44\|/, true] //Looking in the string to match the string '\|44\|'

The boolean at the end could be used to easily inverse the filter?

Just throwing out ideas here...

@kkaefer
Copy link
Member

kkaefer commented May 24, 2017

GeoJSON properties do support arrays, and we have support for parsing them, so I think accessing them as part of the expression syntax is something we should also incorporate.

@1ec5
Copy link
Contributor

1ec5 commented May 24, 2017

Ok, how about a function to match a concated string using regex? :p

Tracked in #4089.

@anandthakker
Copy link
Contributor

Related: #2434

@stevage
Copy link
Contributor

stevage commented Aug 7, 2017

@anandthakker a feature request, not a bug?

@anandthakker
Copy link
Contributor

Whoops, my mistake - thanks @stevage

@jfirebaugh jfirebaugh changed the title Style API: Ability to set a style filter by a looking in a feature property array An expression to check if an array contains a given value Apr 19, 2018
@brncsk brncsk mentioned this issue Aug 25, 2018
6 tasks
@gabrielmsdiniz
Copy link

gabrielmsdiniz commented Jan 13, 2020

I don't think that in operator solves this problem...

Since the first parameter should be the feature property name (string), it is not possible to change the parameters order, like:
['in', 'green', 'colors'] (different behavior)

A contains operator that evaluates the existence of a string in a feature property which type is an array could help...

@ryanhamley
Copy link
Contributor

@gabrielmsdiniz I think I'm confused because what you're describing sounds like what the in operator does.

If you have a feature

{
    'type': 'Feature',
    'geometry': {
        'type': 'Point',
        'coordinates': [
            -77.03238901390978,
            38.913188059745586
        ]
    },
    'properties': {
        'colors': ['red', 'green', 'blue']
    }
}

you could use ['in', 'green', 'colors'] to determine if the string green is in the property colors which is of type array. I'm not sure how the order of the arguments makes a difference.

@gabrielmsdiniz
Copy link

@ryanhamley I don't know why, but I can't do it...
https://jsfiddle.net/gabrielmsd/q4zndpmh/5/

@ryanhamley
Copy link
Contributor

@gabrielmsdiniz The filter syntax has been deprecated; it will still work but you can't mix the filter syntax with the newer expression syntax.
Screen Shot 2020-01-13 at 5 00 55 PM

You'd probably want something like a case expression with in sub-expressions.

'circle-radius': ['case',
    ['in', 'green', 'colors'], 7,
    ['in', 'black', 'colors'], 10,
    ...
]

That being said, the filter docs are confusing because they reference an old in function which was removed from GL JS a long time ago. The docs need to be updated to remove those references since they do not refer to the new in expression. Sorry for that confusion.

@gabrielmsdiniz
Copy link

gabrielmsdiniz commented Jan 14, 2020

@ryanhamley Yes, I'd like to do something like this:

'filter': ['any',
    ['in', 'green', ['get', 'colors']],
    ['in', 'red', ['get', 'colors']]
]

So, how am I supposed to solve this without using filter?

@stevage
Copy link
Contributor

stevage commented Jan 14, 2020

The docs need to be updated to remove those references since they do not refer to the new in expression.

Wait, there's a new "in" expression that does exactly what this issue is requesting? But it's not documented?

@ryanhamley
Copy link
Contributor

@stevage Yes, it was implemented in #8876 Here's an example I made https://codepen.io/rsh412/pen/yLygeZR

I didn't realize that it wasn't appearing in the docs. It was added in the PR so I'm going to have to dig into this to figure out what's up. Obviously we need to retool the docs a bit around this expression. Sorry for the confusion.

cc @mapbox/docs

@stevage
Copy link
Contributor

stevage commented Jan 14, 2020

Oh, cool! I really should start keeping an eye on https://github.com/mapbox/mapbox-gl-js/blob/master/CHANGELOG.md

@ColeAmodeo
Copy link

@ryanhamley Yes, I'd like to do something like this:

'filter': ['any',
    ['in', 'green', ['get', 'colors']],
    ['in', 'red', ['get', 'colors']]
]

So, how am I supposed to solve this without using filter?

Did you ever get an answer? I am having a similar problem where my "in" expression filter is not reading my property array.

@ryanhamley
Copy link
Contributor

ryanhamley commented May 8, 2020

@gabrielmsdiniz @ColeAmodeo The functionality you're attempting to do is possible. See https://jsfiddle.net/rsh412/hue2783p/1/ The original fiddle posted in an earlier comment that appeared not to work was using GL JS 1.4.1 but the in operator was not added until 1.6.0. Newer versions of GL JS should work as expected. If you believe there's a bug, please open a new ticket with a reproducible test case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants