Classify and filter entries based on string in Tableau - tableau-api

I'm trying to filter based on substrings within a string. These strings can contain A through E, or any combination of the five (such as ["C"] or ["A","C","D","E"]). Is there a way I could search through the entire string for each letter before returning a value?
The code I have currently (below) stops when the first IF statement is true. My goal is to be able to classify the entries by the letters in the string and use this calculation as a filter. So, an entry with the string ["A"] would be filtered under "A", but the string ["C","E"] would be filtered under both "C" and "E". Thank you for your help.
IF CONTAINS([Q2.6],"A") then "A"
ELSEIF CONTAINS([Q2.6],"B") then "B"
ELSEIF CONTAINS([Q2.6],"C") then "C"
ELSEIF CONTAINS([Q2.6],"D") then "D"
ELSEIF CONTAINS([Q2.6],"E") then "E"
END

Related

Regex expression in q to match specific integer range following string

Using q’s like function, how can we achieve the following match using a single regex string regstr?
q) ("foo7"; "foo8"; "foo9"; "foo10"; "foo11"; "foo12"; "foo13") like regstr
>>> 0111110b
That is, like regstr matches the foo-strings which end in the numbers 8,9,10,11,12.
Using regstr:"foo[8-12]" confuses the square brackets (how does it interpret this?) since 12 is not a single digit, while regstr:"foo[1[0-2]|[1-9]]" returns a type error, even without the foo-string complication.
As the other comments and answers mentioned, this can't be done using a single regex. Another alternative method is to construct the list of strings that you want to compare against:
q)str:("foo7";"foo8";"foo9";"foo10";"foo11";"foo12";"foo13")
q)match:{x in y,/:string z[0]+til 1+neg(-/)z}
q)match[str;"foo";8 12]
0111110b
If your eventual goal is to filter on the matching entries, you can replace in with inter:
q)match:{x inter y,/:string z[0]+til 1+neg(-/)z}
q)match[str;"foo";8 12]
"foo8"
"foo9"
"foo10"
"foo11"
"foo12"
A variation on Cillian’s method: test the prefix and numbers separately.
q)range:{x+til 1+y-x}.
q)s:"foo",/:string 82,range 7 13 / include "foo82" in tests
q)match:{min(x~/:;in[;string range y]')#'flip count[x]cut'z}
q)match["foo";8 12;] s
00111110b
Note how unary derived functions x~/: and in[;string range y]' are paired by #' to the split strings, then min used to AND the result:
q)flip 3 cut's
"foo" "foo" "foo" "foo" "foo" "foo" "foo" "foo"
"82" ,"7" ,"8" ,"9" "10" "11" "12" "13"
q)("foo"~/:;in[;string range 8 12]')#'flip 3 cut's
11111111b
00111110b
Compositions rock.
As the comments state, regex in kdb+ is extremely limited. If the number of trailing digits is known like in the example above then the following can be used to check multiple patterns
q)str:("foo7"; "foo8"; "foo9"; "foo10"; "foo11"; "foo12"; "foo13"; "foo3x"; "foo123")
q)any str like/:("foo[0-9]";"foo[0-9][0-9]")
111111100b
Checking for a range like 8-12 is not currently possible within kdb+ regex. One possible workaround is to write a function to implement this logic. The function range checks a list of strings start with a passed string and end with a number within the range specified.
range:{
/ checking for strings starting with string y
s:((c:count y)#'x)like y;
/ convert remainder of string to long, check if within range
d:("J"$c _'x)within z;
/ find strings satisfying both conditions
s&d
}
Example use:
q)range[str;"foo";8 12]
011111000b
q)str where range[str;"foo";8 12]
"foo8"
"foo9"
"foo10"
"foo11"
"foo12"
This could be made more efficient by checking the trailing digits only on the subset of strings starting with "foo".
For your example you can pad, fill with a char, and then simple regex works fine:
("."^5$("foo7";"foo8";"foo9";"foo10";"foo11";"foo12";"foo13")) like "foo[1|8-9][.|0-2]"

Drools check if one list contains all elements of another list

How to check whether list of facts contains the list of parameters or attributes present. We want a Rule where The Fact is List of Variables and the attributes which we are passing it is also list of variables. We want to check whether the the Facts contains all the variables present in the List of Attributes . And if it has all the variables matching the Fact then should execute the Action part
when
variable:Fact(names contains( ${names}))
then
System.out.println($listOfNames);
end
This is the example which I have tried. Here the Fact class has the Variable name which is List of String. And ${names} is the attribute which we are passing it as the List of String. So basically we want is that when we pass the list of names in fact it shold see whether it has the variable present from ${names} if yes then should execute. But when we pass list to attribute it gives error which is
11:21:00.868 [main] ERROR o.d.c.k.b.impl.AbstractKieProject.buildKnowledgePackages:276 - Unable to build KieBaseModel:defaultKieBase
Unable to Analyse Expression names contains ( [TaskSpecification3, TaskSpecification4]):
[Error: unable to resolve method using strict-mode: com.drool.example.Fact.TaskSpecification3()]
[Near : {... names contains ( [TaskSpecification3, TaskSpecif ....}]
^ : [Rule name='Rule1_1']
It is not able to rectify bracket, when we pass attributes in the list form it gets print with brackets which gives error.
Is there any way we can Compare that One list contains the parameters from the other List.
I don't even know where to start, that rule's syntax is so wrong.
For your actual question -- how to check if one list contains all elements of another list -- this is a straight-forward ask and there are a number of possible ways to go about it.
From your question, you have a model that looks like this:
class Fact {
List<String> names;
// getters, setters
}
You're passing a Fact instance into your rules, along with a List<String> representing target names. You want your rule to trigger when all of the names in the list in memory are present in the list of names in the fact.
Based on this, your test cases would be something like:
TC | Fact | List | Result
---|--------------------------------|------------------|-------------------
1 | Fact( names: ["A", "B", "C"] ) | List: ["A", "B"] | rule fires / match
2 | Fact( names: ["A", "B", "C"] ) | List: ["A", "D"] | no match
3 | Fact( names: ["A"] ) | List: ["A", "B"] | no match
4 | Fact( names: ["A", "B"] ) | List: ["A", "B"] | rule fires / match
As I mentioned, we can write this rule in several ways. The easiest way to go about this would be to use collect.
rule "Fact check with collect"
when
$names: List( $expected: size )
Fact( $factNames: names )
$matches: List( size == $expected ) from collect(
String( this memberOf $names ) from $factNames
)
then
System.out.println($matches);
end
What we're doing here is straight-forward. First, we get the list of names and assign it to the variable $names. We also save the length of that list to $expected. Then we extract the list of names from Fact and assign it to the variable $factNames.
Next we use collect to iterate over each name in $factNames, check that it is in the $names list, and (if it is), put it into a List called $matches. We check that $matches is the same length as the $names list -- if it is, then the rule triggers and we move to the consequences (right hand side/then.)
More info on collect: see the Drools documentation (search for "Figure 82." to jump as close as you can to the unanchored section about this operator.
If the list of names is not passed as a fact, but is part of the rule, then it simplifies the case further and you can just use in to verify.
Assuming a hard-coded list of ["A", "B", "C"]:
rule "Fact check with collect and hard-coded list"
when
Fact( $factNames: names )
$matches: List( size == 3 ) from collect(
String( this in ("A", "B", "C") ) from $factNames
)
then
System.out.println($matches);
end
Note that in addition to the actual content of the list, you also have to sub in the length of the list in the size == check.
template header
salience
names
namedTags
import com.drool.example.Fact;
import java.util.Map;
import java.util.List;
global java.util.List list;
function Boolean toCompareList(List targetList, List blackList){
Boolean flag = false;
for(Object obj: targetList){
if(blackList.contains(obj)){
flag = true;
break;
}
}
return flag;
}
template "DataWithoutNull"
rule "Rule1_#{row.rowNumber}"
salience #{salience}
dialect "java"
when
$names: Fact($listOfNames:${names})
variable:Fact(toCompareList(names,$listOfNames))
then
System.out.println($names);
end
This is the Drt which I have used. Here we have written a function to check if onle list contains all the element in other function and that function is used in the Condition part where we pass facts and parameters to that function and then it evaluate it and give the result in true or false.
If its true then the action part will be executed or will look for other condition and if false will not execute the action part.
Is this the right way to do it or is there any other method. But this works absolutely fine as we expected. If there is any other method please let me know.

Compare if one string is greater than another in kdb

I want to check which of the two strings in greater, for which I have was using below logic but it fails in few cases
q){$[1b in x>=y;x;y]}["b";"b"]
"b"
q){$[1b in x>=y;x;y]}["c";"b"]
"c"
q){$[1b in x>=y;x;y]}["azz";"dff"] // Wrong output (Reason for failure - "azz">"dff" --> 011b)
"azz" / desired output dff
Please suggest another way to get the greatest string of the provided strings?
Since comparison operator compares character by character hence in "azz" and "dff" if the output can be displayed as "dff" only after comparison for "d" from "dff" and "a" from "azz" as "a" is less than "d".
You can convert the string to symbol and use <, >, etc.. These operators perform lexicographic comparisons for symbols.
https://code.kx.com//q4m3/4_Operators/
q) `azz < `dff
1b
If you insist on strings then you can leverage iasc to creat a "smaller-or-equal"-like function:
q) not first iasc ("azz"; "dff")
1b
Using 1b in is equivalent to any in this case as "azz">"dff" equates to 011b. Your conditional will evaluate true as 2 letters in "azz" are greater than "dff".
It is better to cast x and y to symbols and compare as this will evaluate with 1 boolean:
(`$"azz")>=`$"dff"
0b
{$[(`$x)>=`$y;x;y]}["azz";"dff"]
"dff"
Alternatively you could sort desc order and take the first result:
{first desc(x;y)}["azz";"dff"]
"dff"

Could I specify pattern match priority in lex code?

I've got a related thread in the site(My lex pattern doesn't work to match my input file, how to correct it?)
The problems I met, is about how "greedy" lex will do pattern match, e.g. I've got my lex file:
$ cat b.l
%{
#include<stdio.h>
%}
%%
"12" {printf("head\n");}
"34" {printf("tail\n");}
.* {printf("content\n");}
%%
What I wish to say is, when meet "12", print "head"; when meet "34", print "tail", otherwise print "content" for the longest match that doesn't contain either "12" or "34".
But the fact was, ".*" was a greedy match that whatever I input, it prints "content".
My requirement is, when I use
12sdf2dfsd3sd34
as input, the output should be
head
content
tail
So seems there're 2 possible ways:
1, To specify a match priority for ".*", it should work only when neither "12" and "34" works to match. Does lex support "priority"?
2, to change the 3rd expression, as to match any contiguous string that doesn't contain sub-string of "12", or "34". But how to write this regular expression?
Does (f)lex support priority?
(F)lex always produces the longest possible match. If more than one rule matches the same longest match, the first one is chosen, so in that case it supports priority. But it does not support priority for shorter matches, nor does it implement non-greedy matching.
How to match a string which does not contain one or more sequences?
You can, with some work, create a regular expression which matches a string not containing specified substrings, but it is not particularly easy and (f)lex does not provide a simple syntax for such regular expressions.
A simpler (but slightly less efficient) solution is to match the string in pieces. As a rough outline, you could do the following:
"12" { return HEAD; }
"34" { if (yyleng > 2) {
yyless(yyleng - 2);
return CONTENT;
}
else
return TAIL;
}
.|\n { yymore(); }
This could be made more efficient by matching multiple characters when there is not chance of skipping a delimiter; change the last rule to:
.|[^13]+ { yymore(); }
yymore() causes the current token to be retained, so that the next match appends to the current token rather than starting a new token. yyless(x) returns all but the first x characters to the input stream; in this case, that is used to cause the end delimiter 34 to be rescanned after the CONTENT token is identified.
(That assumes you actually want to tokenize the input stream, rather than just print a debugging message, which is why I called it an outline solution.)

Autohotkey: Splitting a concatenated string into string and number

I am using an input box to request a string from the user that has the form "sometext5". I would like to separate this via regexp into a variable for the string component and a variable for the number. The number then shall be used in a loop.
The following just returns "0", even when I enter a string in the form "itemize5"
!n::
InputBox, UserEnv, Environment, Please enter an environment!, , 240, 120
If ErrorLevel
return
Else
FoundPos := RegExMatch(%UserEnv%, "\d+$")
MsgBox %FoundPos%
retur
n
FoundPos, as its name implies, contains the position of the leftmost occurrence of the needle. It does not contain anything you specifically want to match with your regex.
When passing variable contents to a function, don't enclose the variable names in percent signs (like %UserEnv%).
Your regex \d+$ will only match numbers at the end of the string, not the text before it.
A possible solution:
myText := "sometext55"
if( RegExMatch(myText, "(.*?)(\d+)$", splitted) ) {
msgbox, Text: %splitted1%`nNumber: %splitted2%
}
As described in the docs, splitted will be set to a pseudo-array (splitted1, splitted2 ...), with each element containing the matched subpattern of your regex (the stuff that is in between round brackets).