unable to fetch set from map using java8 - java

what I'm trying to do
Set<A> set=new HashSet();
Map<String,List<String>> map=new HashMap();
if(map.keySet().contains("key"){
for(String str: map.get("key")
{
for(A a : listOfA)
{
if(a.getString().equalsIgnoreCase(str);
set.add(a);
}
}
}
What I tried
if(map.keySet().contains("key")
{
listOfA
.stream()
.filter(t->t.getString().equalsIgnoreCase(map.get("key")
.stream
.flatMap(c->c.toString()))
.distinct()
.collect(Collectors.toSet()):
}
//error The method equalsIgnoreCase(String) in the type String is not
applicable for the arguments (Stream)
if(map.keySet().contains("key")
{
map.get("key").stream().filter(t->t.equals(listOfA.stream().map(a->a.getString()))).collect(Collectors.toSet());
}
and this method returns Set<String>,obviously as output but I want Set<A> as output
so how to solve this, using functional programming

You can check if any String of map.get("key") is equalsIgnoreCase to getString() of a given A instance by streaming map.get("key") and using anyMatch :
List<String> value = map.get("key");
Set<A> set = null;
if (value != null) {
set = listOfA.stream()
.filter(a->value.stream()
.anyMatch(s->a.getString().equalsIgnoreCase(s)))
.collect(Collectors.toSet());
}

The following solution might scale better if your listOfA is rather large:
List<String> value = map.getOrDefault("key", Collections.emptyList());
Collection<String> c;
if(value.isEmpty()) c=value;
else { c=new TreeSet<>(String.CASE_INSENSITIVE_ORDER); c.addAll(value); }
Set<A> set = listOfA.stream()
.filter(a->c.contains(a.getString()))
.collect(Collectors.toSet());

Related

how to convert else if in java8

How to change the below code to remove if-else and use Java8
List<String> list1;
List<String> list2;
List<String> list3;
String str;
if(list1.contains(str)){
event.getMessage().setInvocationProperty("ABC","ABC1");
}
else if(list2.contains(str)){
event.getMessage().setInvocationProperty("ABC2","ABC3");
}
else if(list3.contains(str)){
event.getMessage().setInvocationProperty("ABC4","ABC5");
}
Here is how to do it by creating what I'll call a HoldingObject, but you can name it with something more close to your business.
I'm using Lombok's #Value annotation and also java-9's List#of factory method
#Value
public static class HoldingObject {
List<String> list;
String invocationProperty1;
String invocationProperty2;
public void setInvocationPropertyFor(Event event) {
event.getMessage().setInvocationProperty(invocationProperty1, invocationProperty2);
}
}
Note that doing event.getMessage() repeatedly might not be thread-safe if event is accessed through multiple threads
HoldingObject firstObject = new HoldingObject(list1, ABC, ABC1);
HoldingObject secondObject = new HoldingObject(list1, ABC2, ABC3);
HoldingObject thirdObject = new HoldingObject(list1, ABC4, ABC5);
List.of(firstObject, secondObject, thirdObject)
.stream()
.filter(object -> object.getList().contains(str))
.findFirst()
.ifPresent(h -> h.setInvocationPropertyFor(event));
It is possible to do it without if-else, but for this case, if-else would still be better than using streams.
List<String> list1;
List<String> list2;
List<String> list3;
String str;
Map<List<String>, List<Param>> paramMap = new HashMap<>();
paramMap.put(list1,List.of(ABC,ABC1));
paramMap.put(list2,List.of(ABC2,ABC3));
paramMap.put(list3,List.of(ABC4,ABC5));
List.of(list1,list2,list3)
.stream()
.filter(list -> list.contains(str))
.findFirst()
.ifPresent(list -> event.getMessage().setInvocationProperty(paramMap.get(list).get(0),paramMap.get(list).get(1)));
Another solution without using the list as key in paramMap:
Map<Integer, List<Param>> paramMap = new HashMap<>();
paramMap.put(1,List.of(ABC,ABC1));
paramMap.put(2,List.of(ABC2,ABC3));
paramMap.put(3,List.of(ABC4,ABC5));
List<List<String>> lists = List.of(list1,list2,list3);
List<String> mList = lists.stream()
.filter(list -> list.contains(str))
.findFirst()
.ifPresent(list -> {
Integer index = Integer.valueOf(lists.indexOf(list));
event.getMessage()
.setInvocationProperty(paramMap.get(index).get(0),paramMap.get(index).get(1))
});

Combining to operations using java streams

I'm doing the below two operations
Iterating through a list of Objects and creating a map of String, Boolean based on a condition.
Map<String,Boolean> myMap = new HashMap<>();
Iterator<Person> iterator = personList.iterator();
while (iterator.hasNext()) {
Person person = iterator.next();
if (isValidperson(person)) {
if (person.getName() != null) {
myMap.put(person.getName(), true);
} else {
myMap.put(person.getName(), false);
}
}
}
Now Im checking a list of Names against that map that I created above and if the value is true then adding to a final list
List<String> refinedList = new ArrayList<>();
for (String name : nameList) {
if (myMap.get(name) != null && myMap.get(name)) {
refinedList.add(name);
}
}
I need to simplify the logic using Java streams. The above works fine otherwise.
In the first operation you are filtering out all the non-valid persons, and collecting the valid persons to a map, so:
Map<String,Boolean> myMap = personList.stream()
.filter(YourClass::isValidPerson)
.collect(Collectors.toMap(x -> x.getName(), x -> x.getName() != null))
But really though, the map is going to have at most one false entry, since you can't add multiple nulls into a HashMap, so there isn't much point in using a HashMap at all.
I suggest using a HashSet:
Set<String> mySet = personList.stream()
.filter(YourClass::isValidPerson)
.map(Person::getName)
.filter(Objects::nonNull)
.collect(Collectors.toSet())
And then you can easily check contains with O(1) time:
List<String> refinedList = nameList.stream().filter(mySet::contains).collect(Collectors.toList());
You can directly filter the list by checking contains in nameList and collect the names in list
List<String> refinedList =
personList.stream()
.filter(e -> isValidperson(e))
.map(e -> e.getName())
.filter(Objects::nonNull)
.distinct()
.filter(e -> nameList.contains(e))
.collect(Collectors.toList());
And it better to create a set from nameList to make the contains() operation faster in O(1)
Set<String> nameSet = new HashSet<String>(nameList);
Note: This will works if nameList doesn't contains duplicate.
This should work.
First, create a list of People.
List<Person> personList = List.of(new Person("Joe"),
new Person(null), new Person("Barb"), new Person("Anne"), new Person("Gary"));
Then the nameList. Note it is best to put this in a set to
avoid duplicates, and
make the lookup process more efficient.
Set<String> nameSet = Set.of("Joe", "Anne", "Ralph");
Now this works by
filtering on a valid vs invalid person.
mapping those people to a name
filtering on whether null and then if the name is in the set of names
and placing in a list.
Note: In some cases, lambdas could be replaced by Method References depending on method types and calling contexts.
List<String> names = personList.stream()
.filter(person -> isValidperson(person))
.map(Person::getName)
.filter(name -> name != null && nameSet.contains(name))
.collect(Collectors.toList());
System.out.println(names);
Prints
[Joe, Anne]
Dummy method since criteria not provided
public static boolean isValidperson(Person person) {
return true;
}
Simple person class
class Person {
String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}

Cleanest way to filter objects before adding to a collection?

private List<BusinessObject> createList(int property1, List<String> filenames) {
List<BusinessObject> objectList = new ArrayList();
filenames.forEach(filename -> {
BusinessObject businessObj = parseObject(filename);
if (businessObj.getProperty1() == property1) {
objectList.add(businessObj);
}
});
return objectList;
}
I feel like there must be a more idiomatic or Java 8-ish solution out there, such as
filesnames.forEach(fileName -> parseObject(fileName)).(some method that takes the output of parseObject)
The exact stream equivalent would be:
return filenames.stream()
.map(filename -> parseObject(filename))
.filter(o -> o.getProperty1() == property1)
.collect(Collectors.toCollection(ArrayList::new));

Split csv file using lambda expression

I'm trying to refactor this method to use a lambda expression:
public List<String> getHttpsLinksFromCsvList() {
List<String> data = getDataFromCsv();
List<String> httpLinks = new ArrayList<>();
data.forEach(System.out::println);
for (String value : data) {
String[] arrayString = value.split(COMMA_DELIMITER);
for (String item : arrayString) {
if (item.endsWith(".git")) {
httpLinks.add(item);
}
}
}
//httpLinks.forEach(System.out::println);
return httpLinks;
}
Ideally I want to get remove the two nested for loops and optimise it a bit. Is it possible?
Try this:
List<String> httpLinks = getDataFromCsv().stream()
.map(value -> value.split(COMMA_DELIMITER))
.flatMap(Arrays::stream)
.filter(item -> item.endsWith(".git"))
.collect(Collectors.toList());

How to convert a loop that sometimes adds a transformed value to a Java 8 stream/lambda?

How do you convert this into a Java 8 lambda expression?
List<String> inputStrings = new ArrayList<>(); // say, a list of inputStrings
ArrayList<SomeClass> outputResultStrings = new ArrayList();
for(String anInputString : inputStrings) {
SomeClass someResult = doSomthing(anInputString);
if (someResult != null) {
outputResultStrings.add(someResult);
}
}
Your code essentially loops over the input strings, performs doSomthing on each of them (map in Java's terminology), ignores the results that are null (filter in Java's terminology) and then produces a list of those results (collect in Java's terminology). And when you put it all together:
List<SomeClass> outputResultStrings =
inputStrings.stream()
.map(SomeClass::doSomething)
.filter(x -> x != null)
.collect(Collectors.toList());
EDIT:
As suggested by Tunaki, the not-null check can be cleaned up with Objects::nonNull:
List<SomeClass> outputResultStrings =
inputStrings.stream()
.map(SomeClass::doSomething)
.filter(Objects::nonNull)
.collect(Collectors.toList());
List<String> inputStrings = new ArrayList<>(); // say, a list of inputStrings
List<SomeClass> outputResultStrings = inputStrings.stream()
.map(s -> doSomthing(s))
.filter(e -> e != null)
.collect(Collectors.toList());
ArrayList<SomeClass> list = inputStrings.stream()
.map(SomeClass::doSomthing)
.filter((someClazz)->{
return someClazz!=null;
})
.collect(Collectors.toCollection(ArrayList::new));

Categories