我有一个学生名单a和学生名单B。
学生对象包含如下字段:否、年龄、城市、出生日期、工资
我的列表A包含这些对象
A=[1 , 20 , Rome , 2001, 300 ]
[2 , 21 , Dublin , 2005, 250 ]
[3 , 24 , Istanbul, 2012, 350 ]
[4 , 27 , Madrid , 2002, 450 ]
[5 , 27 , London , 2005, 650 ]
我的列表B包含这些对象
B=[1, 20 , Rome , 2014, 700 ]
[3, 24 , Istanbul, 2012, 350 ]
[4, 27 , Madrid, 2009, 450 ]
我想做的是提取ListA有但listB没有的学生对象,以及ListA和listB有但薪水不同的学生对象(如否、年龄、城市)。我还想写工资差异。
Result set = [5 , 27 ,London, 2005, 650 ]
[2 , 21 ,Dublin ,2005, 250 ]
[1, 20, Rome , 2001, -400]
我想在java 8中使用流api。首先,我想将students对象提取到列表中,但我现在可以提取常见的student对象。我尝试使用noneMatch,但它不起作用。你知道吗?
List<Student> listDiffList = A.stream()
// We select any elements such that in the stream of elements from the second list
.filter(two -> B.stream()
// there is an element that has the same name and school as this element,
.anyMatch(one -> one.getNo().equals(two.getNo())
&& one.getAge().equals(two.getAge())
&& one.getCity().equals(two.getCity())))
// and collect all matching elements from the first list into a new list.
.collect(Collectors.toList());
如果您有两个列表,您只想要一个从列表A中减去列表B的结果列表,最明显的方法是使用List
接口的RemoveAll()
方法:
import java.util.List;
import java.util.ArrayList;
public class Test {
public static void main(String[] args){
List<Integer> listA = List.of(Integer.valueOf(1),
Integer.valueOf(2),
Integer.valueOf(3),
Integer.valueOf(4),
Integer.valueOf(5));
List<Integer> listB = List.of(Integer.valueOf(1),
Integer.valueOf(3),
Integer.valueOf(4));
List<Integer> listResult =
new ArrayList<>(listA); // creating an identical list
listResult.removeAll(listB); // subtract the elements present in list B
System.out.println("listA: " + listA);
System.out.println("listB: " + listB);
System.out.println("listA \"minus\" listB: " + listResult);
System.out.println();
}
}
将打印:
listA: [1, 2, 3, 4, 5]
listB: [1, 3, 4]
listA "minus" listB: [2, 5]
您可以使用流接口来完成它,但它没有那么简单。但是anyMatch()
和noneMatch()
都可以在这里工作。它们都是返回布尔值的“短路终端操作[s]”,因此它们作为谓词是完美的。只需流式传输您的列表A并使用带有谓词的过滤器来删除您不想要的元素。对于anyMatch()
,您将希望过滤掉结果是否为真,因此需要用not颠倒。noneMatch()
非常简单:
List<Integer> listResultStream =
listA.stream()
..然后使用以下任一选项:
.filter(intA ->
!(listB.stream()
.anyMatch(intB -> intB.equals(intA))))
..或:
.filter(intA ->
listB.stream()
.noneMatch(intB -> intB.equals(intA)))
并收集结果:
.collect(Collectors.toList());
对于您的特定场景,我可能不会使用streams解决方案。尽管如此,我后来还是添加了一些。
我用过这个学生班。我决定注释掉出生日期,因为它与解决方案无关:
class Student {
int no;
int age;
String city;
// LocalDate birth_date;
int salary;
// Student(int no, int age, String city, int birth_date, int salary){
Student(int no, int age, String city, int salary){
this.no = no;
this.age = age;
this.city = city;
// this.birth_date = LocalDate.of(birth_date, 1, 1); // January 1st.
this.salary = salary;
}
@Override
public String toString(){
return "(" +
no + ", " +
age + ", " +
city + ", " +
// birth_date + ", " +
salary +
")";
}
由于没有出生日期,我将这些记录用于两个列表:
List<Student> listStudentA = List.of(new Student(1 , 20 , "Rome" , 300 ),
new Student(2 , 21 , "Dublin" , 250 ),
new Student(3 , 24 , "Istanbul", 350 ),
new Student(4 , 27 , "Madrid" , 450 ),
new Student(5 , 27 , "London" , 650 ),
new Student(6 , 27 , "Paris" , 650 ));
List<Student> listStudentB = List.of(new Student(1 , 20 , "Rome" , 700 ),
new Student(3 , 24 , "Istanbul", 350 ),
new Student(4 , 27 , "Madrid" , 450 ),
new Student(6 , 27 , "Paris" , 650 ));
您似乎想要比较列表A中的记录,看看列表B中是否有类似的记录。只有在没有类似匹配的情况下,您才想将该记录添加到结果列表中。如果存在类似的匹配,但几乎完全相同,则需要添加一个新对象。如果存在相同的匹配项,则不会将任何匹配项添加到结果列表中。它就像一个列表。拧动一下removeAll()。
一个常规的双循环是完美的。逐个检查列表A,看看是否可以在列表B中找到类似的记录。找到一条后,检查它是否几乎相同或完全相同。如果快到了,则向结果列表中添加一个新对象。无论哪种方式,都可以在那里停止内部循环。只有当您有一个到达内部循环末尾的记录,而没有找到类似的记录时,才能将该记录添加到结果列表中。可以使用一个标志来检查是否使用布尔值。
List<Student> listStudentDiffLoops = new ArrayList<>();
for (Student studentA : listStudentA) {
boolean found = false;
for (Student studentB : listStudentB) {
if (studentA.no == studentB.no &&
studentA.age == studentB.age &&
studentA.city.equals(studentB.city)) {
found = true; // either add a diffsalary Student or none at all
// if this studentA is different from the found studentB
if (studentA.salary != studentB.salary) {
listStudentDiffLoops
.add(new Student(studentA.no,
studentA.age,
studentA.city,
-Math.abs(studentA.salary - studentB.salary)));
}
break; // We're done comparing this studentA
}
}
// there was no similar studentB
if (!found) listStudentDiffLoops.add(studentA);
}
System.out.println("listStudentDiffLoops = " + listStudentDiffLoops);
这将打印:
listStudentDiffLoops = [(1, 20, Rome, -400), (2, 21, Dublin, 250), (5, 27, London, 650)]
我决定使用-Math.abs使工资差异始终为负,这样对象就不会与实际的
学生
混淆。或者,一个人可以为这些对象创建另一个类:
class StudentSalaryDiff extends Student {
StudentSalaryDiff(int no, int age, String city, int salary){
super(no, age, city, salary);
}
};
对于streams解决方案,您可以将列表a中的每个记录映射到以下任一项:
对于整个列表B,相同的元素ifnoneMatch()
返回true
映射对象后,只需过滤掉空对象。
请注意,在最坏的情况下,这将为列表A中的每个元素流式传输列表B两次。它将始终流式传输列表B以检查
noneMatch()
,如果为false,它将再次流式传输列表B:
List<Student> listStudentDiff =
listStudentA
.stream()
.map(studentA -> {
if (listStudentB
.stream()
.noneMatch(studentB -> // noneMatch returns true or false
(studentA.no == studentB.no &&
studentA.age == studentB.age &&
studentA.city.equals(studentB.city)))) {
return studentA; // The same element
} else { // there is a similar element
int otherSalary =
listStudentB
.stream()
.filter(studentB ->
(studentA.no == studentB.no &&
studentA.age == studentB.age &&
studentA.city.equals(studentB.city)))
.findFirst()
.get() // should not fail since there IS a similar element
.salary;
if (otherSalary == studentA.salary) {
return (Student) null; // null
} else {
return new Student( // a new object
studentA.no,
studentA.age,
studentA.city,
-Math.abs(studentA.salary - otherSalary));
}
}
})
.filter(student -> student != null) // remove null objects.
.collect(Collectors.toList());
如果您喜欢只流式传输列表B一次,您可以使用
findFirst()
或findAny()
,这将仅为您提供一个可能为空也可能不为空的结果。结果在可选
中给出,您可以在其中使用isPresent()
检查是否匹配。
这有点像谢尔盖·阿菲诺热诺夫所接受的答案
此解决方案仍然使用
map()
来返回元素,就像之前的解决方案一样:
List<Student> listStudentDiffOptional =
listStudentA
.stream()
.map(studentA -> {
Optional<Student> similarStudent =
listStudentB
.stream()
.filter(studentB ->
(studentA.no == studentB.no &&
studentA.age == studentB.age &&
studentA.city.equals(studentB.city)))
.findFirst();
if (similarStudent.isPresent()){
int salarydiff = similarStudent.get().salary;
if (salarydiff == studentA.salary) {
return (Student) null; // the two objects are identical
} else {
return new Student(studentA.no,
studentA.age,
studentA.city,
-Math.abs(studentA.salary - salarydiff));
}
} else { // there wasn't a similar object
return studentA;
}
})
.filter(student -> student != null)
.collect(Collectors.toList());
所有代码一气呵成:
import java.util.List;
import java.util.ArrayList;
import java.util.stream.Collectors;
import java.util.Optional;
public class Test {
public static void main(String[] args){
// --------------------------
// -------- simple Integers -
List<Integer> listA = List.of(Integer.valueOf(1),
Integer.valueOf(2),
Integer.valueOf(3),
Integer.valueOf(4),
Integer.valueOf(5));
List<Integer> listB = List.of(Integer.valueOf(1),
Integer.valueOf(3),
Integer.valueOf(4));
List<Integer> listResult =
new ArrayList<>(listA); // creating an identical list
listResult.removeAll(listB); // subtract the elements present in list B
System.out.println("listA: " + listA);
System.out.println("listB: " + listB);
System.out.println("listA \"minus\" listB: " + listResult);
System.out.println();
List<Integer> listResultStream =
listA.stream()
// .filter(intA ->
// !(listB.stream()
// .anyMatch(intB -> intB.equals(intA))))
.filter(intA ->
listB.stream()
.noneMatch(intB -> intB.equals(intA)))
.collect(Collectors.toList());
System.out.println("listA \"minus\" listB using listResultStream: " + listResultStream);
System.out.println();
// ---------------------------
// -------- complex Students -
/*
List<Student> listStudentA = List.of(new Student(1 , 20 , "Rome" , 2001, 300 ),
new Student(2 , 21 , "Dublin" , 2005, 250 ),
new Student(3 , 24 , "Istanbul", 2012, 350 ),
new Student(4 , 27 , "Madrid" , 2002, 450 ),
new Student(5 , 27 , "London" , 2005, 650 ),
new Student(6 , 27 , "Paris" , 2005, 650 ));
List<Student> listStudentB = List.of(new Student(1 , 20 , "Rome" , 2014, 700 ),
new Student(3 , 24 , "Istanbul", 2012, 350 ),
new Student(4 , 27 , "Madrid" , 2009, 450 ),
new Student(6 , 27 , "Paris" , 2005, 650 ));
*/
List<Student> listStudentA = List.of(new Student(1 , 20 , "Rome" , 300 ),
new Student(2 , 21 , "Dublin" , 250 ),
new Student(3 , 24 , "Istanbul", 350 ),
new Student(4 , 27 , "Madrid" , 450 ),
new Student(5 , 27 , "London" , 650 ),
new Student(6 , 27 , "Paris" , 650 ));
List<Student> listStudentB = List.of(new Student(1 , 20 , "Rome" , 700 ),
new Student(3 , 24 , "Istanbul", 350 ),
new Student(4 , 27 , "Madrid" , 450 ),
new Student(6 , 27 , "Paris" , 650 ));
List<Student> listStudentDiffLoops = new ArrayList<>();
// --------------------------
// -------- for loops -------
for (Student studentA : listStudentA) {
boolean found = false;
for (Student studentB : listStudentB) {
if (studentA.no == studentB.no &&
studentA.age == studentB.age &&
studentA.city.equals(studentB.city)) {
found = true; // either add a diffsalary Student or none at all
// if this studentA is different from the found studentB
if (studentA.salary != studentB.salary) {
listStudentDiffLoops
.add(new Student(studentA.no,
studentA.age,
studentA.city,
-Math.abs(studentA.salary - studentB.salary)));
}
break; // We're done comparing this studentA
}
}
// there was no similar studentB
if (!found) listStudentDiffLoops.add(studentA);
}
System.out.println("listStudentDiffLoops = " + listStudentDiffLoops);
// --------------------------
// -------- streaming twice -
List<Student> listStudentDiff =
listStudentA
.stream()
.map(studentA -> {
if (listStudentB
.stream()
.noneMatch(studentB ->
(studentA.no == studentB.no &&
studentA.age == studentB.age &&
studentA.city.equals(studentB.city)))) {
return studentA; // The same element
} else { // there is a similar element
int otherSalary =
listStudentB
.stream()
.filter(studentB -> // noneMatch returns true or false
(studentA.no == studentB.no &&
studentA.age == studentB.age &&
studentA.city.equals(studentB.city)))
.findFirst()
.get() // should not fail since there IS a similar element
.salary;
if (otherSalary == studentA.salary) {
return (Student) null; // null
} else {
return new Student( // a new object
studentA.no,
studentA.age,
studentA.city,
-Math.abs(studentA.salary - otherSalary));
}
}
})
.filter(student -> student != null) // remove null objects.
.collect(Collectors.toList());
System.out.println("listStudentDiff: " + listStudentDiff);
// --------------------------
// -------- using optional --
List<Student> listStudentDiffOptional =
listStudentA
.stream()
.map(studentA -> {
Optional<Student> similarStudent =
listStudentB
.stream()
.filter(studentB ->
(studentA.no == studentB.no &&
studentA.age == studentB.age &&
studentA.city.equals(studentB.city)))
.findFirst();
if (similarStudent.isPresent()){
int salarydiff = similarStudent.get().salary;
if (salarydiff == studentA.salary) {
return (Student) null; // the two objects are identical
} else {
return new Student(studentA.no,
studentA.age,
studentA.city,
-Math.abs(studentA.salary - salarydiff));
}
} else { // there wasn't a similar object
return studentA;
}
})
.filter(student -> student != null)
.collect(Collectors.toList());
System.out.println("listStudentDiffOptional: " + listStudentDiffOptional);
}
}
// ------------------------------
// ------------------------------
class Student {
int no;
int age;
String city;
// LocalDate birth_date;
int salary;
// Student(int no, int age, String city, int birth_date, int salary){
Student(int no, int age, String city, int salary){
this.no = no;
this.age = age;
this.city = city;
// this.birth_date = LocalDate.of(birth_date, 1, 1); // January 1st.
this.salary = salary;
}
@Override
public String toString(){
return "(" +
no + ", " +
age + ", " +
city + ", " +
// birth_date + ", " +
salary +
")";
}
}
class StudentSalaryDiff extends Student {
StudentSalaryDiff(int no, int age, String city, int salary){
super(no, age, city, salary);
}
};
我使用了自定义收集器对象,看起来不是很好,但似乎可以工作:
List<Student> listDiffList =
A.stream()
.collect(ArrayList::new,
(a, two) -> {
Optional<Student> one = B.stream()
.filter(s -> s.getNo().equals(two.getNo())
&& s.getAge().equals(two.getAge())
&& s.getCity().equals(two.getCity()))
.findAny();
if (one.isPresent()) {
if (!one.get().getSalary().equals(two.getSalary())) {
two.setSalary(two.getSalary()-one.get().getSalary());
a.add(two);
}
}
else a.add(two);
},
ArrayList::addAll);
我试图理解Java8流。我有两门课: 以及: 字段应指示全天的卡路里总量是否为。该字段与当天的所有条目相同。 我试图从
问题内容: 我有以下Java6和Java8代码: Java8中有什么方法可以使用Lambda以更简洁的方式处理前一个问题? 问题答案: 流绑定到给定的可迭代/集合,因此您不能真正地“并行”迭代两个集合。 一种解决方法是创建索引流,但不一定比for循环有所改进。流版本可能如下所示:
我有一个要求,我需要根据2个条件从另一个列表中创建一个对象列表。对象应处于会话中或处于活动状态。[这个问题与使用java8流从另一个对象创建对象列表有着模糊的联系 主要类别: 任何帮助都将不胜感激。
我在下面使用JDK7进行了探讨
问题内容: 我有看起来像的数据框: 为了进一步处理数据,我需要拆分该列,然后将其替换为如下所示的多列: 因此,这些列可以追加到初始数据帧。我不知道该怎么做,因为像 不能解决我的问题,因为我不仅需要基于列表中位置的列,还需要基于列表中每个唯一值的列。您知道我该如何处理吗? 问题答案: 您可以使用和: 如果需要计数值,则可以使用(我添加一个字符串进行测试):
我有两个对象列表,它们在两个列表中都有重复名称。我需要从清单2中删除清单1中的所有重复值。 下面是一个场景,类有名称变量,用这个变量需要检查清单1中的重复值并需要删除。 //这是具有3个对象的第一个列表 清单1大小为1 请建议我在Java8与流。