Mapbox - setFilter expression for 'Contains' name within array of possible values - expression

I'm trying filter my Mapbox layer (mapboxgl) to return just places that start with say 'North', 'South, 'East' or 'West'.
My places are in geojson data as a property.
I'm using map.setFilter with an expression to filter the geojson.
Example:
map.setFilter('markers', ["all",filter1,filter2]);
Where filter2 is a simple check on if the place is 'open' or 'closed' and filter1 is my main filter expression explained below.
The main issue is that the name of the place needs to START with one of these values.
So far I can do this IF the strings to check are all the same length by grabbing the length of the strings and then filtering by that substring of the name.
But this doesn't work (obviously) when I have words that are not the same length.
This is pretty simple in most other languages, but my brain cant figure out this in mapbox's expression filters for some reason!
Here's what I have so far (please excuse the poor code quality here, I'm not a professional coder!!):
//the array data to check for a match
filterArray = ['North','South','East','West'];
//checks first values length - not ideal!
var lengthToCheck = filterArray[0].length;
//apply it to the filter to only return ones starting with X
filter1 = ['in', ['slice',['to-string', ['get', 'name']],0,lengthToCheck], ['literal', filterArray]];
I have to slice the name of the place as it might be for example 'Northampton', which wont be found within the array value[0] being 'North'.
This is equally as bad code for the 'East' values as the name slice is going to be 5 characters, so it will be trying something like 'Eastb' (Eastbourne) within the array value 'East' which just wont work.
It would be good if I could some how flip this round so the filter can check the values in the array within the Name, but I can't figure this out!
Is there a way to do that or is there a magic expression feature I'm missing that would solve this problem?
I'm also going to have the same problem with a 'Contains' type check of an array of values too, but I'll cross that bridge once I figure this part out!
Any help appreciated (before I go putting in some convoluted workaround!).

Related

Extract substring using importxml and substring-after

Using Google sheet 'ImportXML', I was able to extract the following data from a url(in cell A2) using:
=IMPORTXML(A2,"//a/#href[substring-after(., 'AGX:')]").
Data:
/vector/AGX:5WH
/vector/AGX:Z74
/vector/AGX:C52
/vector/AGX:A27
/vector/AGX:C6L
But, I want to extract the code after "/vector/AGX:". The code is not fixed to 3 letters and number of rows is not fixed as well.
I used =INDEX(SPLIT(AP2,"/,'vector',':'"),1,2). But it applied to only one line of data. Had to copy the index+split function to the whole column and had to insert an additional column to store the codes.
5WH
Z74
C52
A27
C6L
But, I want to be able to extract the code(s) after AGX: using ImportXML in one go. Is there a way?
Solution
Your issue is in how you are implementing the index formula. The first parameter returns the rows (in your case each element) and the second the column (in your case either AGX or the code after that).
If instead of getting a single cell we apply this formula on a range and we do not set any value for the row, the formula will return all the values achieving what you were aiming for. Here is its implementation (where F1:F5 will be the range of values you want this formula to be applied) :
=INDEX(SPLIT(F1:F5,"/,'vector',':'"),,2)
If you are interested in a solution simply using IMPORTXML and XPATH, according to the documentation you could use a substring as follows:
=IMPORTXML(A1,"//a/#href[substring-after(.,'SGX:')]")
The drawback of this is that it will return the full string and not exclusively what is after the SGX: which means that you would need to use a Google sheet formula to splitting this. This is the furthest I have achieved exclusively using XPath. In XML it would be easier to apply a forEach and really select what is after the : but I believe in sheets is more complicated if not impossible just using XPath.
I hope this has helped you. Let me know if you need anything else or if you did not understood something. :)

assistance needed constructing JSONata query

I am trying to construct a JSONata query using the try.jsonata.org Invoice data.
The query I am trying to pose is select distinct OrderID where Order.Product.Price is < 50?
I have not been able to figure out how to do this using the predicate in square brackets notation ... my attempts have been thwarted when I try to get past the $.Account.Order.Product array.
Using $map and $reduce I was able to come up with this rather complex solution ... which still doesn't correctly handle duplicate OrderIDs. (I see that the issue of duplicate removal has been requested here)
Q: What is the proper way to express this query in JSONata?
I think this does what you need:
Account.Order[Product.Price.($ < 50)].OrderID
The expression in the predicate, which gets tested for each Order, will generate an array of Booleans (one for each Product.Price). The resulting predicate will evaluate to true if any of the Booleans within that array are true, due to the semantics of the $boolean function which is implicitly applied.
Overall, the expression will return the OrderID for every Order which has at least one Product whose Price is less than 50

Using except operator with property condition

I have two lists with different objects. Both objects have a string property name that I need for comparing.
I need to know what values in list A are not contained in list B based on the name property.
Would the except operator work for this case?
What would be a optimal way to achive this in Linq?
Except operator removes items based on object equality. Although you could shoehorn your scenario into Except by passing an "equality comparer" that pays attention only to Name property, the resultant code would be hard to understand.
A better approach is to make a set of names that you wish to exclude, and use that set in your query:
var excludedNames = new HashSet<string>(listB.Select(item => item.Name));
var result = listA.Where(item => !excludedNames.Contains(item.Name)).ToList();

Report Builder Expressions

Im new to Report Builder and having issues with some expressions that Im trying to implement in a report. I got the standard ones to work however as soon as I try any distinctions, I get error messages. Over the last couple weeks, Ive tried many combinations, read the expression help, google and looking at other questions at internet sites. To reduce my frustrations, I even would jump to other expressions and walk away hoping I would have different insight coming back.
Its probably something simple or something I dont know about writing expressions.
Im hoping that someone can help with these expressions; they are the versions I get the least errors with(usually just expression expected) and show what Im trying to accomplish.
=IIF((Fields!RECORDFLAG.Value)='D',COUNTDISTINCT(Fields!TICKETNUM.Value),0)
=IIF((Fields!TRANSTYPE.Value)='1' and (Fields!RECORDFLAG.VALUE)='A' or
'B',SUM(Fields!DOLLARS.Value),0)
=IIF((Fields!TRANSTYPE.Value)='1' and
(Fields!RECORDFLAG.VALUE)='P',SUM(Fields!DOLLARS.Value),0)
=Sum([DOLLARS] case when [RECORDFLAG]='P' then -1*[DOLLARS])
Thank You.
=IIF((Fields!RECORDFLAG.Value)=”D”,COUNTDISTINCT(Fields!TICK‌​ETNUM.Value))
The error message gives you the answer here - no false part of the iif() has been specified. Use =IIF((Fields!RECORDFLAG.Value)=”D”,COUNTDISTINCT(Fields!TICK‌​ETNUM.Value), 0)
=IIF((Fields!TRANSTYPE.Value)="1" and (Fields!RECORDFLAG.VALUE)="A" or "B",SUM(Fields!DOLLARS.Value),0)
This is not how an OR works in SSRS. Use:
=IIF((Fields!TRANSTYPE.Value)="1" and (Fields!RECORDFLAG.VALUE="A" or Fields!RECORDFLAG.Value = "B"),SUM(Fields!DOLLARS.Value),0)
The 0s are returned due to your report design. countdistinct() is an aggregate function - it's meant to be used on a set of data. However, your iif() is only testing on a per row basis - you're basically saying "if the current row is thing, count all the distinct values" which doesn't make sense. There are a couple of ways forward:
You can count the number of times a certain value occurs in a given condition using a sum(). This is not the same as the countdistinct(), but if you use =sum(iif(Fields!RECORDFLAG.Value = "D", 1, 0)) then you will get the number of times RECORDFLAG is D in that set. Note: this requires the data to be aggregated (so in SSRS, grouped in a tablix).
You can use custom code to count distinct values in a set. See https://itsalocke.com/aggregate-on-a-lookup-in-ssrs/. You can apply this even if you have only one dataset - just reference the same one twice.
You can change the way your report works. You can group on Fields!RECORDFLAG.Value and filter the group to where Fields!RECORDFLAG.Value = "D". Then in your textbox, use =countdistinct(Fields!TICKETNUM.Value) to get the distinct values for TICKETNUM when RECORDFLAG is D.

How to check whether a value exists in a Ruby structure?

I used to have a series of independent arrays (e.g. name(), id(), description() ). I used to be able to check whether a value existed in a specific array by doing name.include?("Mark")
Now that I moved to a MUCH MORE elegant way to manage different these independent arrays (here for background: How do I convert an Array with a JSON string into a JSON object (ruby)) I am trying to figure out how I do the same.
In short I put all the independent arrays in a single structure so that I can reference the content as object().name, object().id, object().description.
However I am missing now how I can check whether the object array has a value "Mark" in its name structure.
I have tried object.name.include?("Mark") but it doesn't quite like it.
I have also tried to use has_value?but that doesn't seem to be working either (likely because it used to be an hash before I imported it into the structure but right now is no longer a hash - see here: How do I convert an Array with a JSON string into a JSON object (ruby))
Thoughts? How can I check whether object.name contains a certain string?
Thanks.
If you want to find all customers called Mark you can write the following:
customers_named_mark = array_of_customers.select{|c| c.name == 'Mark' }
This will return a potentially empty array.
If you want to find the first customer named Mark, write
customer_named_mark = array_of_customers.detect{|c| c.name == 'Mark' }
This will return the first matching item or nil.

Resources