Java - Find Element in Array using Condition and Lambda - java

In short, I have this code, and I'd like to get an specific element of the array using a condition and lambda. The code would be something like this:
Preset[] presets = presetDALC.getList();
Preset preset = Arrays.stream(presets).select(x -> x.getName().equals("MyString"));
But obviously this does not work. In C# would be something similar but in Java, how do I do this?

You can do it like this,
Optional<Preset> optional = Arrays.stream(presets)
.filter(x -> "MyString".equals(x.getName()))
.findFirst();
if(optional.isPresent()) {//Check whether optional has element you are looking for
Preset p = optional.get();//get it from optional
}
You can read more about Optional here.

Like this:
Optional<Preset> preset = Arrays
.stream(presets)
.filter(x -> x.getName().equals("MyString"))
.findFirst();
This will return an Optional which might or might not contain a value. If you want to get rid of the Optional altogether:
Preset preset = Arrays
.stream(presets)
.filter(x -> x.getName().equals("MyString"))
.findFirst()
.orElse(null);
The filter() operation is an intermediate operation which returns a lazy stream, so there's no need to worry about the entire array being filtered even after a match is encountered.

Do you want first matching, or all matching?
String[] presets = {"A", "B", "C", "D", "CA"};
// Find all matching
List<String> resultList = Arrays.stream(presets)
.filter(x -> x.startsWith("C"))
.collect(Collectors.toList());
System.out.println(resultList);
// Find first matching
String firstResult = Arrays.stream(presets)
.filter(x -> x.startsWith("C"))
.findFirst()
.orElse(null);
System.out.println(firstResult);
Output
[C, CA]
C

One-liner since Java 8:
Preset found = Stream.of(presets)
.filter(p -> p.getName().equals("MyString"))
.findFirst().orElseThrow();
Avoid declaring Optional<>, that returned from findFirst as a variable or a parameter. It is designed for return types / "one-liner" styles.
see javadoc API Note
see 26 Reasons Why Using Optional Correctly

Related

Perform a filter within a function call

Is there a way I could perform a filter within the steps of the following function call?
The following works fine but I wish to add a null/empty check on getResults which returns a list of Results object.
I could try to .stream() on it like getResults().stream().filter();
But kind of pointless since getResults().stream() could potentially throw a null pointer already.
Also this returns a stream of Result. But I want to do a check on the List of Result itself, like:
.filter(CollectionUtils::isNotEmpty)
Is there a way to do this?
public MyFunc(Helper helper) {
Function<String, HttpEntity<Request>> createRequestFunction = helper::createRequest;
this.fetch = createRequestFunction
.andThen(helper::getResponse)
.andThen(Response::getQuery)
.andThen(QueryResult::getResults)
// I want to make a filter here .filter(CollectionUtils::isNotEmpty) to ensure
// getResults (It is a List<Result> type) is not null or empty
.andThen(results -> results.stream()
.map(Result::getKey)
.filter(StringUtils::isNotBlank)
.map(s -> s.split("\\|"))
.filter(data -> data.length == 2)
.map(data -> data[1])
.collect(Collectors.toList()));
}
createRequestFunction has type of Function<String, HttpEntity<Request>>
Function itself doesn't have a filter operation. It is possible to either append additional function via andThen or prepend via compose.
What is expected behaviour if QueryResult::getResults is null? What is the value of this.fetch should be?
One possible option is to wrap result of QueryResult::getResults into an Optional. Something similar to this:
this.fetch = createRequestFunction
.andThen(helper::getResponse)
.andThen(Response::getQuery)
.andThen(QueryResult::getResults)
.andThen(Optinal::ofNullable);
so the result of this.fetch is Optinal<List<Result>> and it is possible to execut different logic based on the fact if optional is empty or not.
e.g
return
this.fetch // Optinal<List<Result>>
.getOrElse(Collections.emptyList()) // value of optional if it is not empty, or empty list otherwise
.stream()
.map(Result::getKey)
.filter(StringUtils::isNotBlank)
.map(s -> s.split("\\|"))
.filter(data -> data.length == 2)
.map(data -> data[1])
.collect(Collectors.toList())

Convert List of Set<String> to Set<String> using JAVA 8 Streams

Is there any possibility to convert a List of Set to Set using java 8 streams.
Here my List :
// Get Header Columns to display in EXCEL FILE
List<Set<String>> keysQuery = listExtractQglobal.parallelStream()
.map(m -> m.keySet()).distinct().collect(Collectors.toList());
Thanks
Just use a flatMap
Set<String> a = keysQuery.stream().flatMap(s -> s.stream()).collect(Collectors.toSet());
As the comment indicated you can also replace the lambda function with lambda reference
Set<String> a = keysQuery.stream().flatMap(Set::stream).collect(Collectors.toSet());
Assuming this is how you create your list:
List<Set<String>> keysQuery = listExtractQglobal.parallelStream()
.map(m -> m.keySet()).distinct().collect(Collectors.toList());
you can actually avoid unnecessary collecting to a list and collect to a set instead:
Set<String> keysQuery = listExtractQglobal.parallelStream()
.map(Map::keySet)
.distinct()
.flatMap(Collection::stream)
.collect(Collectors.toSet());
Btw, I'm not sure why do you need the distinct here. Are you looking for distinct sets or distinct keys among all key sets? In latter case you could simply omit the distinct(), since the resulting Set contains distinct values by definition:
Set<String> keysQuery = listExtractQglobal.parallelStream()
.map(Map::keySet)
.flatMap(Collection::stream)
.collect(Collectors.toSet());
I would use Stream#mapMulti from java-16 instead of Stream#flatMap as it has an overhead of possibly creating empty or very small streams
Set<String> keysQuery = listExtractQglobal.parallelStream()
.map(Map::keySet)
.mapMulti((Set<String> set, Consumer<String> consumer) -> {
set.forEach(consumer::accept);
})
.collect(Collectors.toSet());

Converting nested optional list to optional list in Java?

I have an optionalIdList ( Optional<Set<String>> optionalIdList) that I want to iterate over, and then convert back to Optional<Set<String>>. My code thus far is like this:
optionalIdList
.map(
idList ->
idList.stream()
.map(
id ->
filterIds(
partnerIds
)))
.flatMap(streamOfLists -> streamOfLists.map(item -> item.orElseGet(ImmutableSet::of)));
The filterIds list returns Optional<Set<String>>
However with my current solution I get the following error:
Required type: Optional<Set<String>>
Provided: Optional<Object>
Is there a nice way to do what I want to do?
EDIT: For some reason I assumed filterIds returns a single String, and not an Optional<Set<String>> as you wrote it does.
Here's the updated answer:
Optional<Set<String>> output =
optionalIdList.map(idList -> idList.stream()
.map(id -> filterIds(partnerIds))
.filter (Optional::isPresent)
.map (Optional::get)
.flatMap (Set::stream)
.collect(Collectors.toSet()));

How to get all values from List of Map in Scala?

I have list of Map.
List(Map(term_id -> 20898477-2374-4d4c-9af0-8ed9c9829c94),
Map(term_id -> 6d949993-1593-4491-beae-eb9bf8abcf27),
Map(term_id -> 1123c413-3ffd-45ed-8215-dd1bccb3a48f))
and want to get all value and check if a term_id already exist in above list of Map.
This can be done with iterating list and checking value of each map. But I want something more efficient and one liner. I am okay with either of Java or Scala approach.
This question may be naive, but I am not getting at how to proceed. I am new to Java/Scala.
Expected Output:
List(20898477-2374-4d4c-9af0-8ed9c9829c94, 6d949993-1593-4491-beae-eb9bf8abcf27,
123c413-3ffd-45ed-8215-dd1bccb3a48f)
I think flatMap is what you want:
val maplist=List(Map("term_id" -> "20898477-2374-4d4c-9af0-8ed9c9829c94"), Map("term_id" -> "6d949993-1593-4491-beae-eb9bf8abcf27"), Map("term_id" -> "1123c413-3ffd-45ed-8215-dd1bccb3a48f"))
maplist.flatMap(_.values)
//res0: List[String] = List(20898477-2374-4d4c-9af0-8ed9c9829c94, 6d949993-1593-4491-beae-eb9bf8abcf27, 1123c413-3ffd-45ed-8215-dd1bccb3a48f)
maplist.flatMap(_.keys)
//res1: List[String] = List(term_id, term_id, term_id)
you can use below code to get list of values
val maplist=List(Map("term_id" -> "20898477-2374-4d4c-9af0-8ed9c9829c94"), Map("term_id" -> "6d949993-1593-4491-beae-eb9bf8abcf27"), Map("term_id" -> "1123c413-3ffd-45ed-8215-dd1bccb3a48f"))
maplist.map(x=>x.get("term_id")
Output:
List[Option[String]] = List(Some(20898477-2374-4d4c-9af0-8ed9c9829c94), Some(6d949993-1593-4491-beae-eb9bf8abcf27), Some(1123c413-3ffd-45ed-8215-dd1bccb3a48f))

Existing condition into JAVA 8 stream

How can i convert the below condition to Java 8 streams way ?
List<String> name = Arrays.asList("A", "B", "C");
String id;
if(name.contains("A")){
id = "123";
}else if(name.contains("B")){
id = "234";
}else if(name.contains("C")){
id = "345";
}
I am in process of learning Streams and was wondering how i can convert this one. I tried with foreach, map, filter but it was not getting at it
Yet another (but compact) solution:
Arrays.asList("B", "C", "A", "D").stream()
.map(s -> s.equals("A") ? new SimpleEntry<>(1, "123")
: s.equals("B") ? new SimpleEntry<>(2, "234")
: s.equals("C") ? new SimpleEntry<>(3, "345")
: null)
.filter(x -> x != null)
.reduce((a, b) -> a.getKey() < b.getKey() ? a : b)
.map(Entry::getValue)
.ifPresent(System.out::println);
I cannot see why do you have to convert it to stream. This doesn't seem to be stream API case for me.
But if you want to easily add new items and make code more readable, I can suggest you to use map instead.
private static final ImmutableMap<String, String> nameToId = new ImmutableMap.Builder<String, String>()
.put("A", "123")
.put("B", "234")
.put("C", "345")
.build();
Now you can add new items without changing much code and just call nameToId.get(name) to fetch id by name.
You can add more flexibility here using streams
Stream.of("A", "B", "C").map(nameToId::get)collect(Collectors.toList());
Inspired by Serghey Bishyr's answer to use a map I also used a map (but ordered) and I will rather go through the keys of the map instead of the list to find the appropriate id. That might of course not be the best solution, but you can play with Streams that way ;-)
Map<String, String> nameToId = new LinkedHashMap<>();
// the following order reflects the order of your conditions! (if your first condition would contain "B", you would move "B" at the first position)
nameToId.put("A", "123");
nameToId.put("B", "234");
nameToId.put("C", "345");
List<String> name = Arrays.asList("A", "B", "C");
String id = nameToId.keySet()
.stream()
.filter(name::contains)
.findFirst()
.map(nameToId::get)
.orElse(null)
You gain nothing really... don't try to put too much into the filtering predicates or mapping functions, because then your Stream solution might not be that readable anymore.
The problem you describe is to get a single value (id) from application of a function to two input sets: the input values and the mappings.
id = f(list,mappings)
So basically your question is, to find a f that is based on streams (in other words, solutions that return a list don't solve your problem).
First of all, the original if-else-if-else construct mixes three concerns:
input validation (only considering the value set "A","B","C")
mapping an input value to an output value ("A" -> "123", "B" -> "234", "C" -> "345")
defining an implicit prioritization of input values according to their natural order (not sure if that is intentional or conincidental), "A" before "B" before "C"
When you want to apply this to a stream of input value, you have to make all of them explicit:
a Filter function, that ignores all input value without a mapping
a Mapper function, that maps the input to the id
a Reduce function (BinaryOperator) the performs the prioritization logic implied by the if-else-if-else construct
Mapping Function
The mapper is a discrete function mapping the input values to a one-element-stream of outputput values:
Function<String,Optional<String>> idMapper = s -> {
if("A".equals(s)){
return Optional.of("123");
} else if("B".equals(s)){
return Optional.of("234");
} else if("C".equals(s)){
return Optional.of("345");
}
return Optional.empty();
} ;
For more mappings an immutable map should be used:
Map<String,String> mapping = Collections.unmodifiableMap(new HashMap<String,String>(){{
put("A", "123");
put("B", "234");
put("C", "345");
}}); //the instance initializer is just one way to initialize the map :)
Function<String,Optional<String>> idMapper = s -> Optional.ofNullable(mapping.get(s));
Filter Function
As we only allow input values for which we have a mapping, we could use the keyset of the mapping map:
Predicate<String> filter = s -> mapping.containsKey(s);
Reduce Function
For find the top-priority element of the stream using their natural order, use this BinaryOperator:
BinaryOperator<String> prioritizer = (a, b) -> a.compareTo(b) < 0 ? a : b;
If there is another logic to prioritize, you have to adapt the implementation accordingly.
This operator is used in a .reduce() call. If you prioritize based on natural order, you could use .min(Comparator.naturalOrder()) on the stream instead.
Because the natur
Stream Pipeline
Now you first have to reduce the stream to a single value, using the prioritizer, the result is an Optional which you flatMap by applying the idMapper function (flatMap to not end with Optional>
Optional<String> id = Arrays.asList("C", "B", "A")
.stream()
.filter(filter) //concern: input validation
.reduce(prioritizer) //concern: prioritization
.flatMap(idMapper); //concern: id-mapping
Final Result
To wrap it up, for your particular problem, the most concise version (without defining functions first) using a stream and input validation would be:
//define the mapping in an immutable map (that's just one way to do it)
final Map<String,String> mapping = Collections.unmodifiableMap(
new HashMap<String,String>(){{
put("A", "123");
put("B", "234");
put("C", "345");
}});
Optional<String> result = Arrays.asList("C", "D", "A", "B")
.stream()
.filter(mapping::containsKey)
.min(Comparator.naturalOrder())
.flatMap(s -> Optional.ofNullable(mapping.get(s)));
which is the sought-for f:
BiFunction<List<String>,Map<String,String>,Optional<String>> f =
(list,map) -> list.stream()
.filter(map::containsKey)
.min(Comparator.naturalOrder())
.flatMap(s -> Optional.ofNullable(mapping.get(s)));
There is certainly some appeal to this approach, but the elegance-through-simplicity of the if-else approach cannot be denied either ;)
But for the sake of completeness, let's look at complexity. Assuming the number of mappings and the number of input values is rather large (otherwise it wouldn't really matter).
Solutions based on iterating over the map and searching using contains (as in your if-else construct):
Best-Case: o(1) (first branch in the if-else construct, first item in list)
Worst-Case: O(n^2) (last branch in the if-else construct, last item in list)
For the streaming solution with reduce, you have to iterate completely through the input list (O(n)) while the map lookup is O(1)
Best-Case: o(n)
Worst-Case: O(n)
Thx to Hamlezz for the reduce idea and Holger for pointing out that applying the mapper function directly to the stream does not yield the same result (as first match wins and not the first entry in the if-else construct) and the min(Comparator.naturalOrder()) option.

Categories

Resources