Drools check if one list contains all elements of another list - drools

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.

Related

Flutter remove whitespace, commas, and brackets from List when going to display as a String

I want to go through my list of strings, and add it to a text element for display, but I want to remove the commas and remove the [] as well as the whitespace, but leave the symbols except the commas and brackets.
So if the List is.
[1,2,#3,*4,+5]
In the text field I want it to show - "12#3*4+5"
I can figure out how to display it, but Im using
Text(myList.tostring().replaceAll('[\\]\\,\\', '')
Is there a way to do this?
You should use the reduce method on your list.
List<String> myList = ["1", "2", "#3", "*4", "+5"];
String finalStr = myList.reduce((value, element) {
return value + element;
});
print(finalStr);
# output: "12#3*4+5"
This method reduces a collection to a single value by iteratively combining elements of the collection using the provided function.
The method takes a function that receives two parameters: one is the current concatenated value, which starts out with the value of the first element of your list, and the second parameter is the next element on your list. So you can do something with those two values, and return it for the next iterations. At last, a single reduced value is returned. In this case, using strings, the code in my answer will concatenate the values. If those were numbers, the result would be a sum of the elements.
If you want to add anything in between elements, simply use the return value. For instance, to separate the elements by comma and whitespace, it should look like return value + " ," + element;.
Unless I'm misunderstanding the question, the most obvious solution would be to use List.join().
List<String> myList = ["1", "2", "#3", "*4", "+5"];
print( myList.join() );
// Result
// 12#3*4+5
You could also specify a separator
print( myList.join(' ') );
// Result
// 1 2 #3 *4 +5

Classify and filter entries based on string in Tableau

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

Drools: difference between contains and memberof

I'm reading Drools 6.4.0 documentation. I'm not sure to have understood the difference between contains and memberof operators: both work with collections and it seems that the only difference is that contains expect the contained object on the right side while memberof expect it on the left side, so they would be equivalent but I'm afraid I'm missing something.
This exemple is taken from Laune's answer to :
Drools: Match local string from array in LHS of rule
rule "ruleY"
when
Data( $los: listOfStrings )
MyObject( string memberOf $los )
then
//do stuff
end
rule "ruleY"
when
MyObject( $s: string )
Data( listOfStrings contains $s )
then
//do stuff
end
They are complementary. Use the one or the other depending of the data you are having and the most logical way to express things.

finding index of key in an ordered dictionary in powershell

I am having a little bit of trouble with hashtables/dictionaries in powershell. The most recent roadblock is the ability to find the index of a key in an ordered dictionary.
I am looking for a solution that isn't simply iterating through the object.
(I already know how to do that)
Consider the following example:
$dictionary = [Ordered]#{
'a' = 'blue';
'b'='green';
'c'='red'
}
If this were a normal array I'd be able to look up the index of an entry by using IndexOf().
[array]::IndexOf($dictionary,'c').
That would return 2 under normal circumstances.
If I try that with an ordered dictionary, though, I get -1.
Any solutions?
Edit:
In case anyone reading over this is wondering what I'm talking about. What I was trying to use this for was to create an object to normalize property entries in a way that also has a numerical order.
I was trying to use this for the status of a process, for example:
$_processState = [Ordered]#{
'error' = 'error'
'none' = 'none'
'started' = 'started'
'paused' = 'paused'
'cleanup' = 'cleanup'
'complete' = 'complete'
}
If you were able to easily do this, the above object would give $_processState.error an index value of 0 and ascend through each entry, finally giving $_processState.complete an index value of 5. Then if you compared two properties, by "index value", you could see which one is further along by simple operators. For instance:
$thisObject.Status = $_processState.complete
If ($thisObject.Status -ge $_processState.cleanup) {Write-Host 'All done!'}
PS > All done!
^^that doesn't work as is, but that's the idea. It's what I was aiming for. Or maybe to find something like $_processState.complete.IndexNumber()
Having an object like this also lets you assign values by the index name, itself, while standardizing the options...
$thisObject.Status = $_processState.paused
$thisObject.Status
PS > paused
Not really sure this was the best approach at the time or if it still is the best approach with all the custom class options there are available in PS v5.
It can be simpler
It may not be any more efficient than the answer from Frode F., but perhaps more concise (inline) would be simply putting the hash table's keys collection in a sub expression ($()) then calling indexOf on the result.
For your hash table...
Your particular expression would be simply:
$($dictionary.keys).indexOf('c')
...which gives the value 2 as you expected. This also works just as well on a regular hashtable... unless the hashtable is modified in pretty much any way, of course... so it's probably not very useful in that case.
In other words
Using this hash table (which also shows many of the ways to encode 4...):
$hashtable = [ordered]#{
sample = 'hash table'
0 = 'hello'
1 = 'goodbye'
[char]'4' = 'the ansi character 4 (code 52)'
[char]4 = 'the ansi character code 4'
[int]4 = 'the integer 4'
'4' = 'a string containing only the character 4'
5 = "nothing of importance"
}
would yield the following expression/results pairs:
# Expression Result
#------------------------------------- -------------
$($hashtable.keys).indexof('5') -1
$($hashtable.keys).indexof(5) 7
$($hashtable.keys).indexof('4') 6
$($hashtable.keys).indexof([char]4) 4
$($hashtable.keys).indexof([int]4) 5
$($hashtable.keys).indexof([char]'4') 3
$($hashtable.keys).indexof([int][char]'4') -1
$($hashtable.keys).indexof('sample') 0
by the way:
[int][char]'4' equals [int]52
[char]'4' has a "value" (magnitude?) of 52, but is a character, so it's used as such
...gotta love the typing system, which, while flexible, can get really really bad at times, if you're not careful.
Dictionaries uses keys and not indexes. OrderedDictionary combines a hashtable and ArrayList to give you order/index-support in a dictionary, however it's still a dictionary (key-based) collection.
If you need to get the index of an object in a OrderedDictionary (or a hasthable) you need to use foreach-loop and a counter. Example (should be created as a function):
$hashTable = [Ordered]#{
'a' = 'blue';
'b'='green';
'c'='red'
}
$i = 0
foreach($key in $hashTable.Keys) {
if($key -eq "c") { $i; break }
else { $i++ }
}
That's how it works internaly too. You can verify this by reading the source code for OrderedDictionary's IndexOfKey method in .NET Reference Source
For the initial problem I was attempting to solve, a comparable process state, you can now use Enumerations starting with PowerShell v5.
You use the Enum keyword, set the Enumerators by name, and give them an integer value. The value can be anything, but I'm using ascending values starting with 0 in this example:
Enum _ProcessState{
Error = 0
None = 1
Started = 2
Paused = 3
Cleanup = 4
Complete = 5
Verified = 6
}
#the leading _ for the Enum is just cosmetic & not required
Once you've created the Enum, you can assign it to variables. The contents of the variable will return the text name of the Enum, and you can compare them as if they were integers.
$Item1_State = [_ProcessState]::Started
$Item2_State = [_ProcessState]::Cleanup
#return state of second variable
$Item2_state
#comparison
$Item1_State -gt $Item2_State
Will return:
Cleanup
False
If you wanted to compare and return the highest:
#sort the two objects, then return the first result (should return the item with the largest enum int)
$results = ($Item1_State,$Item2_State | Sort-Object -Descending)
$results[0]
Fun fact, you can also use arithmetic on them, for example:
$Item1_State + 1
$Item1_State + $Item2_State
Will return:
Paused
Verified
More info on Enum here:
https://blogs.technet.microsoft.com/heyscriptingguy/2015/08/26/new-powershell-5-feature-enumerations/
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_enum?view=powershell-6
https://psdevopsug.scot/post/working-with-enums-in-powershell/

Searching with multiple keys and "begins with"

What's the best way to perform the following type of search in a collection named "things":
mylist = ['lak', 'dodg', 'ang']
and the return could be:
["lake", "Lakers", "laky", "dodge", "Dodgers", "Angels", "angle"]
Would I need to perform a separate query for each?
To do this you want to use the mongodb command $in to search for all things that match with something in your array.
The command you would use would be:
db.things.find( {name: { $in: mylist }} )
But for this to work you want to be using regular expressions in your array, so you can either define them in the array, or if you want to maintain strings then the best thing to do it probably just create another array and loop through and create regex from the strings.
mylist = [/^lak/i, /^dodg/i, /^ang/i]
The ^ making it match only if it begins with the value, and the i at the end to make the search case insensitive.