Jexl
Jexl copied to clipboard
Filtering primitive arrays
How does one filter primitive arrays. ie,
var array = ['a','b','c']
jexl.eval("array[? == 'b']|tranform")
How do you reference the element rather than a property of the element?
If you need to filter by a known logic chain, that's achievable through a custom transform. However, if you're looking to filter against a conditional specified inside the expression, that is currently unsupported.
See PR https://github.com/TechnologyAdvice/Jexl/pull/3 which addresses this. The context of that PR is a .map()
function, but the concept is the same-- a function can be specified inline to be run iteratively over an array's contents. That PR, while aging, is still in consideration for after the 2.0 release. It'll need to be in a different form though, as it currently allows some broken syntax without failing out. Beware that, if you use it.
I'm really interested to hear more about your use case though. I never made array filtering a part of Jexl core because the use cases seemed limited there. I'm always happy to have my mind changed by folks with new perspectives though! :)
Hi Tom,
So it is actually in conjunction with the "map" transform that the issue arises. I'm basically trying to map a filtered primitive array to an object. I have implemented a "filter" transform as a work around, but I think it would be a bit cleaner to offer some sort of access to the root value in the array. Maybe just a '.' without a key, so:
jexl.eval("array[. == 'b']");
What do you think?
The dot notation is interesting! The downside versus the map syntax in #3 is that the dot wouldn't be available in further-nested subexpressions, but I suppose collection filtering has the same downside so it's at least idiomatic. It's just so damn intuitive if you already know how to filter collections -- really nice idea.
Could you give more details surrounding what kind of filter you plan to put in place with a Jexl expression? Specifically, your example above would just result in an array with zero or more b
values-- but I know that was just a simplified case for this discussion :) I'd love to hear if you're looking for a >
conditional in there, or running a transform that will have a true or false result... wrapping my head around a real world use case for this would be great.
Thanks so much! I'm pumped about this-- it could solve a lot of the problems we faced with the syntax issues in #3 and deliver almost all the same functionality.
Actually the use case is merely to detect length of the filtered array. So the real world use case is we store a bunch of status codes in an array. ['good','poor','good','bad'] and I want to know how many are 'good'.
There are many ways to skin this cat, but I thought filter + length was a bit more expressive than a "counting" transform. Feel free to close this if you think it's more trouble than it's worth.
jexl.eval("array[. == 'b']");
seems to be a good implementation, @TomFrost any update on this so far?
Long-overdue update:
I've been playing with solutions here and convinced myself not to use the dot for this, due to it already functioning as a context navigation element and a relative navigation indicator. But given how often I get requests to refer to the root context option, I'm currently working with a new solution to this problem.
I'm planning to add @
, which will refer to the root of the current relative context. That means that evaluating an expression of just @
will return the entire context object. Within an array filter like myArray[@ == 'b']
, the @
will refer to the array element being evaluated. In a collection filter, the expression myCollection[.age > 25]
will simply be shorthand for myCollection[@.age > 25]
I'm open to comments if anyone has any thoughts!