Java 8 - remove items of list in list - java-8

I have this lists in lists:
List<List<ScheduleContainer>> scheduleIntervalContainersOfWeek
and my aim is to have this list
List <List<ScheduleContainer>> scheduleIntervalContainersOfWeek
with ScheduleIntervalContainers where interspace is null oder false.
Therefore I will first convert all ScheduleContainers into ScheduleIntervalContainer (ScheduleContainer is base class of SchedueIntervalContainer) and then I will remove all ScheduleIntervalContainer where field interspace of ScheduleIntervalContainer is true.
I have tried it with:
scheduleIntervalContainersOfWeek.stream().filter(...)
but I don't know the lambda expression in filter method.
Currently I have solved this problem like this:
for (final List<ScheduleContainer> scheduleContainers : scheduleIntervalContainersOfWeek) {
for (final ScheduleContainer scheduleContainer : scheduleContainers) {
final ScheduleIntervalContainer scheduleIntervalContainer = (ScheduleIntervalContainer)scheduleContainer;
// if sic is absence container than continue (absence sics are shown in schedule)
if (scheduleIntervalContainer.getInterspace()) {
continue;
}

Try this:
scheduleContainers = scheduleContainers.stream()
.filter(sc -> !Boolean.TRUE.equals(((ScheduleIntervalContainer)sc).getInterspace()))
.collect(Collectors.toList());
Note the use of a Yoda condition to avoid the need for a null check.

Related

Spring Data JPA filtering by best match

I want to implement filtering for multiple fields of an entity which is ordered by best match. By best match I mean that the more of the filtered fields match the higher in the order the result is listed. I want this to work dynamically, so I can add more filters later on.
I have been looking for a solution for a long time now and I didn't find an elegant way to do this with JPA.
My approach is to concatenate all my predicates with or and then order them by how many of the fields match. This is done by dynamically creating a CASE statement for each possible combination of the filters (this is a powerset and leads to a lot of CASE statements). Then I give every subset a rank (= size of the subset) and then I sort by the rank in descending order. This way subsets with more elements (= filters) are ranked higher.
From a few tests I can see that I already takes up to 10s for 4 filters, so that can't be a good solution.
Here is my code:
private fun orderByBestMatch(): Specification<User?> {
return Specification<User?> { root: Root<User?>, query: CriteriaQuery<*>, builder: CriteriaBuilder ->
val benefit = getExpressionForNestedClass<String>(root, "benefit")
val umbrellaTerm = getExpressionForNestedClass<String>(root, "umbrellaTerm")
val specialization = getExpressionForNestedClass<String>(root, "specialization")
val salaryExpectation = root.get<Number>("salaryExpectation")
val matcher: CriteriaBuilder.Case<Int> = builder.selectCase()
for (set in powerSetOfsearchedFields()) {
if(set.isNotEmpty()) {
var predicate: Predicate? = when(set.elementAt(0).key) {
"umbrellaTerm" -> builder.like(umbrellaTerm, set.elementAt(0).value.toString())
"specialization" -> builder.like(specialization, set.elementAt(0).value.toString())
"benefit" -> builder.like(benefit, set.elementAt(0).value.toString())
"salaryExpectation" -> builder.equal(salaryExpectation, set.elementAt(0).value.toString())
else -> null
}
for (i in 1 until set.size) {
predicate = when(set.elementAt(1).key) {
"umbrellaTerm" -> builder.and(predicate, builder.like(umbrellaTerm, set.elementAt(1).value.toString()))
"specialization" -> builder.and(predicate, builder.like(specialization, set.elementAt(1).value.toString()))
"benefit" -> builder.and(predicate, builder.like(benefit, set.elementAt(1).value.toString()))
"salaryExpectation" -> builder.and(predicate, builder.equal(salaryExpectation, set.elementAt(1).value.toString()))
else -> null
}
}
matcher.`when`(predicate, set.size)
}
}
matcher.otherwise(0)
query.orderBy(builder.desc(matcher))
query.distinct(true)
builder.isTrue(builder.literal(true))// just here for the function to have a return value
// result?.toPredicate(root, query, builder)
}
}
This function is used in a Builder class I implemented and is appended to the Specification with an and when building the Specification.
The Specification is then passed to UserRepository.findall().
Is there a better way (maybe even an out of the box way) to implement this behaviour?
Thanks in advance

How to get an element at a specific index in an Optional List?

Optional<List<Long>> optionalList = getList(someInput);
How do i retrieve an element from this list?
How to iterate this list?
You can unwrap the list and use it like a normal list.
List<Long> list = optionalList.orElseGet(Collections::emptyList);
list.forEach(System.out::println); // process the list
// e.g. printing its elements
If you just want a forEach(..) and don't need the list unwrapped.
optionalList.orElseGet(Collections::emptyList)
.forEach(System.out::println);
You can check if is present
if (optionalList.isPresent()) {
List<Long> myList = optionalList.get();
// process list present
} else {
// process not present
}
Or keep using optional to access to one of its elements
Optional<Long> longAt5 = optionalList.filter(list -> list.size() > 5)
.map(list -> list.get(5));
Check if there is a value present and then do some logic:
optionalList.ifPresent(list -> {
...
});
As for processing the list, you could do:
optionalList.orElseGet(() -> Collections.emptyList()).forEach(e -> {...});

how to convert forEach to lambda

Iterator<Rate> rateIt = rates.iterator();
int lastRateOBP = 0;
while (rateIt.hasNext())
{
Rate rate = rateIt.next();
int currentOBP = rate.getPersonCount();
if (currentOBP == lastRateOBP)
{
rateIt.remove();
continue;
}
lastRateOBP = currentOBP;
}
how can i use above code convert to lambda by stream of java 8? such as list.stream().filter().....but i need to operation list.
The simplest solution is
Set<Integer> seen = new HashSet<>();
rates.removeIf(rate -> !seen.add(rate.getPersonCount()));
it utilizes the fact that Set.add will return false if the value is already in the Set, i.e. has been already encountered. Since these are the elements you want to remove, all you have to do is negating it.
If keeping an arbitrary Rate instance for each group with the same person count is sufficient, there is no sorting needed for this solution.
Like with your original Iterator-based solution, it relies on the mutability of your original Collection.
If you really want distinct and sorted as you say in your comments, than it is as simple as :
TreeSet<Rate> sorted = rates.stream()
.collect(Collectors.toCollection(() ->
new TreeSet<>(Comparator.comparing(Rate::getPersonCount))));
But notice that in your example with an iterator you are not removing duplicates, but only duplicates that are continuous (I've exemplified that in the comment to your question).
EDIT
It seems that you want distinct by a Function; or in simpler words you want distinct elements by personCount, but in case of a clash you want to take the max pos.
Such a thing is not yet available in jdk. But it might be, see this.
Since you want them sorted and distinct by key, we can emulate that with:
Collection<Rate> sorted = rates.stream()
.collect(Collectors.toMap(Rate::getPersonCount,
Function.identity(),
(left, right) -> {
return left.getLos() > right.getLos() ? left : right;
},
TreeMap::new))
.values();
System.out.println(sorted);
On the other hand if you absolutely need to return a TreeSet to actually denote that this are unique elements and sorted:
TreeSet<Rate> sorted = rates.stream()
.collect(Collectors.collectingAndThen(
Collectors.toMap(Rate::getPersonCount,
Function.identity(),
(left, right) -> {
return left.getLos() > right.getLos() ? left : right;
},
TreeMap::new),
map -> {
TreeSet<Rate> set = new TreeSet<>(Comparator.comparing(Rate::getPersonCount));
set.addAll(map.values());
return set;
}));
This should work if your Rate type has natural ordering (i.e. implements Comparable):
List<Rate> l = rates.stream()
.distinct()
.sorted()
.collect(Collectors.toList());
If not, use a lambda as a custom comparator:
List<Rate> l = rates.stream()
.distinct()
.sorted( (r1,r2) -> ...some code to compare two rates... )
.collect(Collectors.toList());
It may be possible to remove the call to sorted if you just need to remove duplicates.

Selecting first items in GroupBy when using custom Class

I have a very basic sql view which joins 3 tables: users, pictures, and tags.
How would one create the query below in a way that it won't list the same pictures more than once? In other words, I want to Group By pictures (I think) and return get the first insance of each.
I think this is very similar to the post Linq Query Group By and Selecting First Items, but I cannot figure out how to apply it in this case where the query is instantiating MyImageClass.
validPicSummaries = (from x in db.PicsTagsUsers
where x.enabled == 1
select new MyImageClass {
PicName = x.picname,
Username= x.Username,
Tag = x.tag }).Take(50);
To exclude duplicates, you can use the Distinct LINQ method:
validPicSummaries =
(from x in db.PicsTagsUsers
where x.tag == searchterm && x.enabled == 1
select new MyImageClass
{
PicName = x.picname,
Username= x.Username,
Tag = x.tag
})
.Distinct()
.Take(50);
You will need to make sure that the objects are comparable so that two MyImageClass objects that have the same PicName, Username, and Tag are considered equal (or however you wish to consider two of them as being equal).
You can write a small class that implements IEqualityComparer<T> if you would like to have a custom comparer for just this case. Ex:
private class MyImageClassComparer : IEqualityComparer<MyImageClass>
{
public bool Equals(MyImageClass pMyImage1, MyImageClass pMyImage2)
{
// some test of the two objects to determine
// whether they should be considered equal
return pMyImage1.PicName == pMyImage2.PicName
&& pMyImage1.Username == pMyImage2.Username
&& pMyImage1.Tag == pMyImage2.Tag;
}
public int GetHashCode(MyImageClass pMyImageClass)
{
// the GetHashCode function seems to be what is used by LINQ
// to determine equality. from examples, it seems the way
// to combine hashcodes is to XOR them:
return pMyImageClass.PicName.GetHashCode()
^ pMyImageClass.UserName.GetHashCode()
^ pMyImageClass.Tag.GetHashCode();
}
}
Then when you call distinct:
...
.Distinct(new MyImageClassComparer())
.Take(50);

Search a particular item between Two Custom List

I have 2 lists of type List<Course>
List<Course> courseTakenFilterListByStatus
List<Course> TakenCoursesNotApplied
I want to find if courseTakenFilterListByStatus.Id is present in the TakenCoursesNotApplied list. Then I need to update Boolean property IsRequired to TRUE. If the value will not be there the property should be set to False.
I don't understand what it has to do with linq.
couldn't you just do the following:
foreach (Course course in courseTakenFilterListByStatus){
// Possibility 1
course.IsRequired = TakenCoursesNotApplied.Contains(course);
// Possibility 2
course.IsRequired = TakenCoursesNotApplied.Any(c => c.Id == course.Id);
}
Don't know if i understodd the logic right. Possibly you have to negate the assigment.
HTH Tobi

Resources