英文:
Is there any way to break the Java Stream with custom condition and collect all the items till the condition matches to the list using Java 8
问题
Question: 我有一个包含 List<Object> 的集合,需要在 **Java 8** 中根据以下条件进行过滤,
1. 将列表中的对象按日期降序排列(其中日期也可以为空)
2. 逐个迭代列表中的每个元素,并验证某些条件,如果条件匹配,则仅中断迭代并返回所有符合条件的元素(直到条件不匹配为止),并忽略剩余的元素。
代码片段:
public class Employee {
private int empId;
private String empName;
private Date empDob;
//构造函数
//Getter和Setter
}
测试类:
public static void main(String[] args) {
List<Employee> asList = Arrays.asList(new Employee(1, "Emp 1", getDate(1998)),
new Employee(2, "Emp 2", getDate(2005)), new Employee(3, "Emp 3", getDate(2000)),
new Employee(4, "Emp 4", null), new Employee(5, "Emp 5", getDate(1990)),
new Employee(6, "Emp 6", new Date()));
List<Employee> result = asList.stream()
.sorted(Comparator.comparing(Employee::getEmpDob, Comparator.nullsLast(Comparator.reverseOrder())))
.filter(i -> i.getEmpName() != null && !StringUtils.isEmpty(i.getEmpName())
&& i.getEmpName().equals("Emp 3"))
.collect(Collectors.toList());
System.out.println(result);
}
public static Date getDate(int year) {
Calendar c1 = Calendar.getInstance();
c1.set(year, 01, 01);
return c1.getTime();
}
我尝试过的上述代码只返回与条件匹配的元素,结果如下:
[Employee [empId=3, empName=Emp 3, empDob=Wed Feb 01 15:55:57 MYT 2000]]
> 我需要的预期输出如下:
我期望的结果如下(它应该收集所有符合条件的元素):
[Employee [empId=6, empName=Emp 6, empDob=Sat Aug 15 16:06:22 MYT 2020],
Employee [empId=2, empName=Emp 2, empDob=Tue Feb 01 16:06:22 MYT 2005],
Employee [empId=3, empName=Emp 3, empDob=Tue Feb 01 16:06:22 MYT 2000]]
英文:
Question: I have some collection List<Object> which need to be filtered with below condition in Java 8,
- Arrange the object in the list in a descending order of date (where date can be null as well)
- Iterate each elements of the list one-by-one and validate some condition, if condition matches, then break the iteration their only and return all the elements(till the condition matches) and ignore the remaining elements.
Code snippet:
public class Employee {
private int empId;
private String empName;
private Date empDob;
//Constructor
//Getter Setter
}
Test Class:
public static void main(String[] args) {
List<Employee> asList = Arrays.asList(new Employee(1, "Emp 1", getDate(1998)),
new Employee(2, "Emp 2", getDate(2005)), new Employee(3, "Emp 3", getDate(2000)),
new Employee(4, "Emp 4", null), new Employee(5, "Emp 5", getDate(1990)),
new Employee(6, "Emp 6", new Date()));
List<Employee> result = asList.stream()
.sorted(Comparator.comparing(Employee::getEmpDob, Comparator.nullsLast(Comparator.reverseOrder())))
.filter(i -> i.getEmpName() != null && !StringUtils.isEmpty(i.getEmpName())
&& i.getEmpName().equals("Emp 3"))
.collect(Collectors.toList());
System.out.println(result);
}
public static Date getDate(int year) {
Calendar c1 = Calendar.getInstance();
c1.set(year, 01, 01);
return c1.getTime();
}
The above code which I tried is returning only the element which is matches with the condition and result is:
[Employee [empId=3, empName=Emp 3, empDob=Wed Feb 01 15:55:57 MYT 2000]]
> Expected Output which I need to do:
The result which I am expecting is something like below (it should collect all the elements till the condition matches)
[Employee [empId=6, empName=Emp 6, empDob=Sat Aug 15 16:06:22 MYT 2020],
Employee [empId=2, empName=Emp 2, empDob=Tue Feb 01 16:06:22 MYT 2005],
Employee [empId=3, empName=Emp 3, empDob=Tue Feb 01 16:06:22 MYT 2000]]
答案1
得分: 4
-
自己实现
Accumulator
和Collector
result = asList.stream().collect(ArrayList::new, (l, e) -> { if (l.isEmpty() || !l.get(l.size() - 1).getEmpName().equals("Emp 3")) l.add(e); }, (l1, l2) -> { if (l1.isEmpty() || !l1.get(l1.size() - 1).getEmpName().equals("Emp 3")) l1.addAll(l2); });
-
要求 JAVA>=9: 使用
Stream.takeWhile()
获取在停止之前的所有元素,然后检索要停止的元素// 添加所有在第一个 Emp3 之前的元素 List<Employee> result = asList.stream() .sorted(comparing(Employee::getEmpDob, nullsLast(reverseOrder()))) .takeWhile(i -> i.getEmpName() != null && !i.getEmpName().isEmpty() && !i.getEmpName().equals("Emp 3")) .collect(Collectors.toList()); // 添加第一个 Emp3 asList.stream() .sorted(comparing(Employee::getEmpDob, nullsLast(reverseOrder()))) .filter(i -> i.getEmpName() != null && !i.getEmpName().isEmpty() && i.getEmpName().equals("Emp 3")) .findFirst().ifPresent(result::add);
这些方法都不是很优雅,但似乎没有更好的方法。
英文:
I'd suggest the solutions of Picking elements of a list until condition is met with Java 8 Lambdas
-
Do your own
Accumulator
andCollector
result = asList.stream().collect(ArrayList::new, (l, e) -> { if (l.isEmpty() || !l.get(l.size() - 1).getEmpName().equals("Emp 3")) l.add(e); }, (l1, l2) -> { if (l1.isEmpty() || !l1.get(l1.size() - 1).getEmpName().equals("Emp 3")) l1.addAll(l2); });
-
REQUIRES JAVA>=9: Use
Stream.takeWhile()
to get all the element before stopping then retrieve the element to stop on// Add all element until the first Emp3 List<Employee> result = asList.stream() .sorted(comparing(Employee::getEmpDob, nullsLast(reverseOrder()))) .takeWhile(i -> i.getEmpName() != null && !i.getEmpName().isEmpty() && !i.getEmpName().equals("Emp 3")) .collect(Collectors.toList()); // Add the first Emp3 asList.stream() .sorted(comparing(Employee::getEmpDob, nullsLast(reverseOrder()))) .filter(i -> i.getEmpName() != null && !i.getEmpName().isEmpty() && i.getEmpName().equals("Emp 3")) .findFirst().ifPresent(result::add);
None of them is very nice, but seems there no nice way to it
答案2
得分: 1
你应该获取所选员工的日期,然后筛选出所有日期大于等于他的日期的员工,并进行排序。
List<Employee> asList = Arrays.asList(new Employee(1, "员工 1", getDate(1998)),
new Employee(2, "员工 2", getDate(2005)), new Employee(3, "员工 3", getDate(2000)),
new Employee(4, "员工 4", null), new Employee(5, "员工 5", getDate(1990)),
new Employee(6, "员工 6", new Date()));
Date searchedEmpDate = asList.stream()
.filter(i -> i.getEmpName() != null && !i.getEmpName().isEmpty()
&& i.getEmpName().equals("员工 3")).findAny().get().getEmpDob();
List<Employee> result = asList.stream()
.filter(i -> i.getEmpDob() != null && i.getEmpDob().compareTo(searchedEmpDate) >= 0)
.sorted(Comparator.comparing(Employee::getEmpDob, Comparator.nullsLast(Comparator.reverseOrder())))
.collect(Collectors.toList());
System.out.println(result);
英文:
You should get date of selected employee, and then filter all with date bigger or equals his date, and then sort them.
List<Employee> asList = Arrays.asList(new Employee(1, "Emp 1", getDate(1998)),
new Employee(2, "Emp 2", getDate(2005)), new Employee(3, "Emp 3", getDate(2000)),
new Employee(4, "Emp 4", null), new Employee(5, "Emp 5", getDate(1990)),
new Employee(6, "Emp 6", new Date()));
Date searchedEmpDate = asList.stream()
.filter(i -> i.getEmpName() != null && !i.getEmpName().isEmpty()
&& i.getEmpName().equals("Emp 3")).findAny().get().getEmpDob();
List<Employee> result = asList.stream()
.filter(i -> i.getEmpDob() != null && i.getEmpDob().compareTo(searchedEmpDate) >= 0)
.sorted(Comparator.comparing(Employee::getEmpDob, Comparator.nullsLast(Comparator.reverseOrder())))
.collect(Collectors.toList());
System.out.println(result);
答案3
得分: 1
***Java 9+***
在Java 9及以上版本中,您可以使用takeWhile()方法,示例如下:
List<Employee> result = asList.stream()
.sorted(Comparator.comparing(Employee::getEmpDob, Comparator.nullsLast(Comparator.reverseOrder())))
.takeWhile(Predicate.not(i -> (i.getEmpName() != null && !StringUtils.isEmpty(i.getEmpName())
&& i.getEmpName().equals("Emp 3"))))
.collect(Collectors.toList());
请注意使用了`Predicate.not`,这将在满足条件之前对表达式进行求值(即直到遇到"Emp 3"之前)。`List<Employee> result` 不包括"Emp 3"。如果要添加"Emp 3",
asList.stream()
.sorted(Comparator.comparing(Employee::getEmpDob, Comparator.nullsLast(Comparator.reverseOrder())))
.filter(i -> i.getEmpName() != null && !StringUtils.isEmpty(i.getEmpName())
&& i.getEmpName().equals("Emp 3"))
.collect(Collectors.toCollection(() -> result));
***Java 8+***
您可以按照[此处][1]的描述实现自己的takeWhile方法,或者您可以模拟takeWhile操作(此方法接受已排序列表)
public static <T> List<T> takeWhile(List<T> list, Predicate<T> p) {
int i = 0;
for (T item : list) {
if (!p.test(item)) {
return list.subList(0, i);
}
i++;
}
return list;
}
然后调用方式为 -
List<Employee> employees = takeWhile(asList.stream()
.sorted(Comparator.comparing(Employee::getEmpDob, Comparator.nullsLast(Comparator.reverseOrder())))
.collect(Collectors.toList()), i -> i.getEmpName() != null && !StringUtils.isEmpty(i.getEmpName())
&& i.getEmpName().equals("Emp 3"));
[1]: https://stackoverflow.com/questions/32290278/picking-elements-of-a-list-until-condition-is-met-with-java-8-lambdas
英文:
Java 9+
In java 9+ you can use takeWhile() as -
List<Employee> result = asList.stream()
.sorted(Comparator.comparing(Employee::getEmpDob, Comparator.nullsLast(Comparator.reverseOrder())))
.takeWhile(Predicate.not(i -> (i.getEmpName() != null && !StringUtils.isEmpty(i.getEmpName())
&& i.getEmpName().equals("Emp 3"))))
.collect(Collectors.toList());
Note use of Predicate.not
, this will evaluate expression till condition is met (i.e. till "Emp 3" is NOT encountered. List<Employee> result
doesn't include "Emp 3". To add "Emp 3"
asList.stream()
.sorted(Comparator.comparing(Employee::getEmpDob, Comparator.nullsLast(Comparator.reverseOrder())))
.filter(i -> i.getEmpName() != null && !StringUtils.isEmpty(i.getEmpName())
&& i.getEmpName().equals("Emp 3"))
.collect(Collectors.toCollection(() -> result));
Java 8+
You can implement your own takeWhile as described here or you can simulate takeWhile as (this method takes sorted list)
public static <T> List<T> takeWhile(List<T> list, Predicate<T> p) {
int i = 0;
for (T item : list) {
if (!p.test(item)) {
return list.subList(0, i);
}
i++;
}
return list;
}
and call as -
List<Employee> employees = takeWhile(asList.stream()
.sorted(Comparator.comparing(Employee::getEmpDob, Comparator.nullsLast(Comparator.reverseOrder())))
.collect(Collectors.toList()), i -> i.getEmpName() != null && !StringUtils.isEmpty(i.getEmpName())
&& i.getEmpName().equals("Emp 3"));
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论