How to filter out Flux<Example> that don't contain some value from Flux<String> - project-reactor

So let's say I have a Flux<String> firstLetters containing "A", "B", "C", "D" and Flux<String> lastLetters containing "X", "Y", "Z"
And I have a Flux containing many:
data class Example(val name: String)
And from the whole Flux<Example> I want to split the elements to two variables: one Flux<Example> containing all that name IN ("A", "B", "C", "D") and second Flux<Example> that has name IN ("X", "Y", "Z") and save those two Fluxes two variables.
Is it possible to do so in one flow without doing same logic first for firstLetters and then for lastLetters

Is it possible to do so in one flow without doing same logic first for firstLetters and then for lastLetters
As the problem stands I don't believe so, as you'll have to process each element multiple times (one per each value on the list to see if it contains the value you need.) You can call cache() on the Flux though to ensure that the values are only retrieved once, or convert to another data structure entirely.
Given that you have to re-evaluate anyway, and assuming you still want to stick with raw Flux objects, filterWhen() and any() can be used quite nicely here:
Flux<Example> firstNames = names.filterWhen(e -> firstLetters.any(e.name::contains));
Flux<Example> lastNames = names.filterWhen(e -> lastLetters.any(e.name::contains));
You can of course pull the Predicate out into a separate method if you're concerned about code duplication there.

If Flux<String> firstLetters/lastLetters can be replaced with Set<String> firstLetters/lastLetters then you can easily leverage Flux::groupBy method on Flux<Example> to split it into different groups.
enum Group {
FIRST, LAST, UNDEFINED
}
Group toGroup(Example example) {
if (firstLetters.contains(example.name)) return FIRST;
else if (lastLetters.contain(example.name)) return LAST;
else return UNDEFINED;
}
Flux<GroupedFlux<Group, Example>> group(Flux<Example> examples) {
return examples.groupBy(example -> toGroup(example));
}
You can then get the group by calling GroupedFlux<K, V>::key.

Related

How to find an object by a property from a List of List of objects in dart?

Hello I am new to dart and trying to find an item by property name in a list of list.
class Product{
String id;
String title;
Product(this.id,this.title);
}
void main(){
List<List<Product>> allProdcuts=[
//New Prodcuts
[
Product("1","Hammer"),
Product("3","Nails"),
Product("2","Screws"),
],
futureItems,
//Old Prodcuts
[
Product("4","Rock"),
Product("5","Paper"),
Product("6","Scissor"),
],
//Rare Items
[
Product("7","Plank"),
Product("8","Wires"),
Product("9","Box"),
],
];
print(allProdcuts.where((itemsList)=>itemsList.contains((product)=>product.title='Wires')));
//Returns ()
}
I have tried using for a single List:
List<Product> futureItems= [
Product("101","Galactic Hammer"),
Product("301","Galactic Nails"),
Product("201","Galactic Screws"),
];
print(newProduct.firstWhere((p)=>p.title=='Hammer'));
//Instance of 'Product'
Also tried this:
print(allProdcuts.map((itemList)=>itemList.firstWhere((p)=>p.title=='Nails')));
// Bad state: No elementError: Bad state: No element.
But there is an element with the title='Nails'.I don't understand what I am doing wrong.
You are calling itemList.firstWhere((p)=>p.title=='Nails') on each list, also the ones with no element with title "Nails". Since firstWhere throws if there is no matching value, it does that for two of your three lists. Also, in the example, itemsList.contains(...) does not take a callback, so you are just checking whether a function is in the list, which it isn't. You might want to use any for that, but it won't solve the problem here.
To do this efficiently, I'd probably create helper function:
Product findByTitle(List<List<Product>> allProducts, String title) {
for (var products in allProducts) {
for (var product in products) {
if (product.title == title) return product;
}
}
// Or return `null`.
throw ArgumentError.value(title, "title", "No element with that title");
}
The return in the middle allows you to skip out of the double iteration the moment you have a match, something which is harder to do with firstWhere/map/forEach etc.
One alternative solutions would be:
var product = allProducts.expand((l) => l.where((p) => p.title == title)).first;
which finds all the products with the given title and flattens them into a single iterable, then picks the first one (if there are any). Because iterables are lazy, it will actually stop at the first match.
There are many ways to solve this.
One example is to use the forEach() method:
allProdcuts.forEach(
(List<Product> l)=>l.forEach(
(Product p){
if (p.title=="Nails")
print(p.id);
}
)
);
The for each method receives a function and applies this function to every element on the list. If you have a lists of lists, you can do this twice to get a function applied to each element of the sub lists.
The above code prints 3, which is the desired result.
Another solution would be to flatten the list first, so you can have an easier search later.
print(allProdcuts.any((innerListOfProducts) =>
innerListOfProducts.any((product) => product.title == 'Wires')));
This code will return true if 'Wires' is in the inner list, and false otherwise.

Confusion on "Immutable" lists in F#

Totally newbie question.
I'm still trying to get a grasp on "Immutable" lists in F#.
Lets assume I have a "Visit" defined as:
module Visit =
type Model =
{
Name: string
}
let init row col cel =
{
Name = sprintf "My Name is row: %d col: %d cel: %d" row col cel
}
Now I define a "Cell" that may or may not have one visit:
module Cell =
type Model =
{
Visit: Visit.Model option
}
let setVisit m =
{ m with Visit = Some( Visit.init 9 9 9) }
and lastly I define a "Column" that has a list of cells:
module Column =
type Model =
{
Appointments: Cell.Model list
}
let updateCell (m:Model) =
let newList = m.Appointments |> List.mapi (fun index cell -> if index = 2 then Cell.setVisit cell else cell)
{m with Appointments = newList }
In the Column module, the "updateCell" function is wired to call Cell.setVisit for the 3rd cell. My intent is to replace the "Name" of the "Visit" held by the 3rd cell. My simple questions are:
Is this the correct way to do this?
If I am replacing the Appointments list, is this not changing the "Column" holding the Appointment List? (The Column is immutable, right? ).
Sorry for my confusion.
TIA
First: yes, this is an acceptable, if inefficient way of doing it for lists. Note that you're rebuilding the whole list on every updateCell call, even though most elements in it are the same.
I don't know how many appointments you expect to have in your model in practice. If it's significantly more than three, and if you're always updating the third one, it would be more efficient to cut the list, then glue it back together:
let newList = List.take 2 m.Appointments # [Cell.setVisit m.Appointments.[2]] # List.drop 3 m.Appointments
This way only the first three elements are rebuilt, and the tail of the list is reused.
However, if you need random-access operations, may I suggest using arrays instead? Sure, they're mutable, but they offer much better performance for random-access operations.
Second: no, the syntax { m with ... } does not change the Column. Instead, it creates a new column - a copy of m, but with all fields listed after with updated to new values.

How to find requirements by keywords using DOORS DXL

I have identified 3-5 keywords for every requirement in module-A. Each keyword is separated by a comma. Now I want to search every requirement in module-B to see which of them have words that match each of the key words.
Not sure exactly what you're looking for. You might have to specify if none of these solutions I'm about to propose are exactly what you're looking for.
If you're trying to create a filter which displays only objects with those keywords in your current view, you can create an advanced filter by first going to filter (Tools > Filter > Define) and then select the Advanced button on the bottom left of the filter menu that appears.
At this point you can create custom rules for the filter. I would just create an individual rule for each word with the following definition:
Attribute: Object Text
Condition: contains
Value: <insert word here>
Match Case: uncheck
Regular Expression: uncheck
Then select the Add button to add the rule to the list of available rules in the Advanced Options.
At this point you can select multiple rules in the list of available rules and you can AND/OR these rules together to create a custom filter for the view that you want.
So that's for if you're trying to create a custom view with just objects containing specific words.
If you're talking about writing DXL code to automatically spit out requirements that have a particular word in it. You can use the something that looks like this:
Object o
String s
int offset, len
for o in entire (current Module) do
{
if (isDeleted(o)) continue
s = o."Object Text"""
if findPlainText(s, "<insert word here>", offset, len, false)
{
print identifier(o) // or replace this line with however you want to display object
}
}
Hope this is helpful. Cheers!
Edit:
To perform actions on a comma separated list, one at a time, you can use a while loop with some sort of search function that cuts off words one at a time.
void processWord (string someWord, Module mTarget, Object oSource)
{
Object oTarget
string objID = identifier(oSource)
for oTarget in mTarget do
{
if (<someWord in oTarget Object Text>) // edit function as necessary to do this
{
if (oTarget."Exists""" == "")
oTarget."Exists" = objID
else
oTarget."Exists" = oTarget."Exists" "," objID
}
}
}
int offset, len
string searchCriteria
Module mSource = read("<path of source module>", true)
Module mTarget = edit("<path of target module>", true)
Object oSource
for oSource in mSource do // can use "for object in entire(m)" for all objects
{
if (oSource != rqmt) continue // create conditions specific to your module here
searchCriteria = oSource."Search Criteria"""
while (findPlainText(searchCriteria, ",", offset, len, false))
{
processWord(searchCriteria[0:offset-1], mTarget, oSource)
searchCriteria = searchCriteria[offset+1:]
}
}
processWord(searchCriteria, mTarget, oSource) // for last value in comma separated list

what is a good way to test parsed json maps for equality?

The following code prints:
false
false
true
{{a: b}, {a: b}}
code
import "dart:json" as JSON;
main() {
print(JSON.parse('{ "a" : "b" }') == JSON.parse('{ "a" : "b" }'));
print({ "a" : "b" } == { "a" : "b" });
print({ "a" : "b" }.toString() == { "a" : "b" }.toString());
Set s = new Set();
s.add(JSON.parse('{ "a" : "b" }'));
s.add(JSON.parse('{ "a" : "b" }'));
print(s);
}
I am using json and parsing two equivalent objects, storing them in a Set, hoping they will not be duplicated. This is not the case and it seems to be because the first two lines (unexpectedly?) results in false. What is an efficient way to correctly compare two Map objects assuming each were the result of JSON.parse()?
The recommended way to compare JSON maps or lists, possibly nested, for equality is by using the Equality classes from the following package
import 'package:collection/collection.dart';
E.g.,
Function eq = const DeepCollectionEquality().equals;
var json1 = JSON.parse('{ "a" : 1, "b" : 2 }');
var json2 = JSON.parse('{ "b" : 2, "a" : 1 }');
print(eq(json1, json2)); // => true
For details see this answer which talks about some of the different equality classes: How can I compare Lists for equality in Dart?.
This is a difficult one, because JSON objects are just Lists and Maps of num, String, bool and Null. Testing Maps and Lists on equality is still an issue in Dart, see https://code.google.com/p/dart/issues/detail?id=2217
UPDATE
This answer is not valid anymore, see answer #Patrice_Chalin
This is actually pretty hard, as the == operator on Maps and Lists doesn't really compare keys/values/elements to each other.
Depending on your use case, you may have to write a utility method. I once wrote this quick and dirty function:
bool mapsEqual(Map m1, Map m2) {
Iterable k1 = m1.keys;
Iterable k2 = m2.keys;
// Compare m1 to m2
if(k1.length!=k2.length) return false;
for(dynamic o in k1) {
if(!k2.contains(o)) return false;
if(m1[o] is Map) {
if(!(m2[o] is Map)) return false;
if(!mapsEqual(m1[o], m2[o])) return false;
} else {
if(m1[o] != m2[o]) return false;
}
}
return true;
}
Please note that while it handles nested JSON objects, it will always return false as soon as nested lists are involved. If you want to use this approach, you may need to add code for handling this.
Another approach I once started was to write wrappers for Map and List (implementing Map/List to use it normally) and override operator==, then use JsonParser and JsonListener to parse JSON strings using those wrappers. As I abandoned that pretty soon, I don't have code for it and don't know if it really would have worked, but it could be worth a try.
The matcher library, used from unittest, will do this.

help with oauthService and linkedin

I am trying to iterate over a list of parameters, in a grails controller. when I have a list, longer than one element, like this:
[D4L2DYJlSw, 8OXQWKDDvX]
the following code works fine:
def recipientId = params.email
recipientId.each { test->
System.print(test + "\n")
}
The output being:
A4L2DYJlSw
8OXQWKDDvX
But, if the list only has one item, the output is not the only item, but each letter in the list. for example, if my params list is :
A4L2DYJlSwD
using the same code as above, the output becomes:
A
4
L
2
D
Y
J
l
S
w
can anyone tell me what's going on and what I am doing wrong?
thanks
jason
I run at the same problem a while ago! My solution for that it was
def gameId = params.gameId
def selectedGameList = gameId.class.isArray() ? Game.getAll(gameId as List) : Game.get(gameId);
because in my case I was getting 1 or more game Ids as parameters!
What you can do is the same:
def recipientId = params.email
if(recipientId.class.isArray()){
// smtg
}else{
// smtg
}
Because what is happening here is, as soon as you call '.each' groovy transform that object in a list! and 'String AS LIST' in groovy means char_array of that string!
My guess would be (from what I've seen with groovy elsewhere) is that it is trying to figure out what the type for recipientId should be since you haven't given it one (and it's thus dynamic).
In your first example, groovy decided what got passed to the .each{} closure was a List<String>. The second example, as there is only one String, groovy decides the type should be String and .each{} knows how to iterate over a String too - it just converts it to a char[].
You could simply make recipientId a List<String> I think in this case.
You can also try like this:
def recipientId = params.email instanceof List ? params.email : [params.email]
recipientId.each { test-> System.print(test + "\n") }
It will handle both the cases ..
Grails provides a built-in way to guarantee that a specific parameter is a list, even when only one was submitted. This is actually the preferred way to get a list of items when the number of items may be 0, 1, or more:
def recipientId = params.list("email")
recipientId.each { test->
System.print(test + "\n")
}
The params object will wrap a single item as a list, or return the list if there is more than one.

Resources