英文:
Compare two list of custom objects with individual fields and save to a new list in java
问题
下面是代码的部分中文翻译:
// 我有两个自定义的Java对象列表。
// Class A 类定义如下:
@Data
Class A{
int no;
int age;
int foo;
int bar;
}
// 从数据库填充 aList 和从请求中填充 bList。
List<A> aList = populateFromDB();
List<A> bList = populateFromReq();
// 现在我想要一个第三个列表,其中包含来自 bList 的经过筛选的对象。
// 筛选基于以下标准:
// no 应该匹配;
// age 或 foo 中的任意一个应该不同;
// 示例数据集:
// 输入:
// aList = [{2,20,50,60} , {3,25,40,60} , {4,40,10,20}]
// bList = [{2,10,50,60} , {3,25,50,60} , {4,40,10,20}]
// 输出:
// filteredList = [{2,10,50,60} , {3,25,50,60}]
// bList 中的前两个元素不同,因此它们应该添加到筛选列表中。
// aList 包含来自数据库的记录。
// bList 包含与 aList 相同大小的记录,但有一些不同的元素。
// 需要将 bList 与 aList 进行比较,并找到不同的记录,然后创建一个单独的列表并将这些记录更新到数据库中。
// 我尝试了以下代码:
List<A> filteredList = bList.stream()
.filter(i -> aList.stream()
.anyMatch(j -> (j.getNo() == i.getNo() &&
(j.getAge() != i.getAge() ||
j.getFoo() != i.getFoo())
)
)
)
.collect(Collectors.toList());
// 但是上述代码没有给我期望的结果。它给我了不满足我提到的标准的记录。我不确定我在哪里出错了。
// 我还尝试了以下代码:
List<A> intersect = aList.stream()
.filter(bList::contains)
.collect(Collectors.toList());
// 有人可以帮助我如何基于某些字段比较两个自定义列表并形成一个新列表吗?
这是你提供的代码部分的中文翻译。
英文:
I have 2 custom list of Java objects.
@Data
Class A{
int no;
int age;
int foo;
int bar;
}
List<A> aList = populateFromDB();
List<A> bList = populateFromReq();
Now I want a 3rd list which will contain filtered objects from bList.
The filtering is based on this criteria :
no should match;
age OR foo anyone should differ;
Sample Data set :
Input :
aList = [{2,20,50,60} , {3,25,40,60} , {4,40,10,20}]
bList = [{2,10,50,60} , {3,25,50,60} , {4,40,10,20}]
Output :
filteredList = [{2,10,50,60} , {3,25,50,60}]
// first 2 elements in bList are different hence they should be added to the filtered list.
// aList contains records from DB.
// bList contains records of same size as aList but few elements are different.
// Need to compare bList with aList and find the records that are different and create a separate list and update those records in DB.
I am trying this code :
List<A> filteredList = bList.stream()
.filter(i -> aList.stream()
.anyMatch(j -> (j.getNo() == i.getNo() &&
(j.getAge() != i.getAge() ||
j.getFoo() != i.getFoo())
)
)
)
.collect(Collectors.toList());
But the above is not giving me desired results. It is giving me records which does not fulfil the criteria I have mentioned. I am not sure where I am making wrong.
I have also tried the below code :
List<A> intersect = a.stream()
.filter(b::contains)
.collect(Collectors.toList());
Can anyone help me how to compare 2 custom list based on some fields and form a new list.
UPDATE-1 : Its not about comparing String. So for simplicity sake I am replacing strings with Integers.
UPDATE-2 : Added sample i/p and o/p data.
答案1
得分: 2
我给你的类添加了一个 constructor
构造函数、一个 matches
方法和一个 toString()
方法。matches
方法是为了满足x.equals(x)
为真的自反要求而创建的,因为覆盖 equals
方法无法满足这一要求。
class A {
public A(int no, int age, int foo, int bar) {
this.no = no;
this.age = age;
this.foo = foo;
this.bar = bar;
}
int no;
int age;
int foo;
int bar;
public boolean matches(A a) {
return a.no == this.no && (a.age != this.age || a.foo != this.foo);
}
@Override
public String toString() {
return "A{" + no + ", " + age + ", " + foo + ", " + bar + "}";
}
}
现在生成一些数据:
List<A> aList = new ArrayList<>();
List<A> bList = new ArrayList<>();
Random r = new Random();
for (int i = 0; i < 10; i++) {
aList.add(new A(r.nextInt(5), r.nextInt(5), r.nextInt(5), r.nextInt(5)));
bList.add(new A(r.nextInt(5), r.nextInt(5), r.nextInt(5), r.nextInt(5)));
}
现在打印生成的值:
for (int i = 0; i < aList.size(); i++) {
System.out.printf("aList(%d) = %s bList(%d) = %s%n", i, aList.get(i), i, bList.get(i));
}
接下来:
- 遍历
aList
并检查相应元素是否满足matches
条件。 - 如果满足条件,将
a
添加到结果列表。 - 然后打印结果。
List<A> results = new ArrayList<>();
int i = 0;
for (A a : aList) {
if (a.matches(bList.get(i++))) {
results.add(a);
}
}
System.out.println();
results.forEach(System.out::println);
输出结果将类似于以下内容:
aList(0) = A{0, 1, 4, 1} bList(0) = A{0, 2, 2, 2}
aList(1) = A{1, 4, 0, 3} bList(1) = A{1, 2, 2, 3}
aList(2) = A{1, 1, 1, 4} bList(2) = A{1, 4, 2, 2}
aList(3) = A{0, 4, 3, 3} bList(3) = A{3, 2, 0, 2}
aList(4) = A{0, 4, 3, 1} bList(4) = A{1, 0, 4, 3}
aList(5) = A{3, 2, 3, 1} bList(5) = A{1, 2, 0, 3}
aList(6) = A{4, 3, 0, 2} bList(6) = A{3, 4, 0, 3}
aList(7) = A{4, 3, 2, 4} bList(7) = A{2, 1, 2, 2}
aList(8) = A{0, 3, 4, 3} bList(8) = A{3, 3, 4, 4}
aList(9) = A{1, 3, 3, 4} bList(9) = A{0, 1, 2, 0}
A{0, 1, 4, 1}
A{1, 4, 0, 3}
A{1, 1, 1, 4}
更新的答案:
下面是一种方法,这只有在你的列表声明为 final
或者是有效的 final
时才会生效:
final List<A> aList = List.of(new A(2, 20, 50, 60), new A(3, 25, 40, 60),
new A(4, 40, 10, 20));
final List<A> bList = List.of(new A(2, 10, 50, 60), new A(3, 25, 50, 60),
new A(4, 40, 10, 20));
List<A> results = IntStream.range(0, aList.size())
.filter(k -> aList.get(k).matches(bList.get(k)))
.mapToObj(aList::get).toList();
results.forEach(System.out::println);
输出结果为:
A{2, 20, 50, 60}
A{3, 25, 40, 60}
英文:
I added a constructor
, matches
method and a toString()
method to your class. The matches
method was created since overriding equals would not meet the reflexive requirements where x.equals(x)
is true.
class A {
public A(int no, int age, int foo, int bar) {
this.no = no;
this.age = age;
this.foo = foo;
this.bar = bar;
}
int no;
int age;
int foo;
int bar;
public boolean matches(A a) {
return a.no == this.no && (a.age != this.age || a.foo != this.foo);
}
@Override
public String toString() {
return "A{%d, %d, %d, %d}".formatted(no, age, foo, bar);
}
}
Now generate some data
List<A> aList = new ArrayList<>();
List<A> bList = new ArrayList<>();
Random r = new Random();
for (int i = 0; i < 10; i++) {
aList.add(new A(r.nextInt(5), r.nextInt(5), r.nextInt(5),
r.nextInt(5)));
bList.add(new A(r.nextInt(5), r.nextInt(5), r.nextInt(5),
r.nextInt(5)));
}
Now print the generated values.
for (int i = 0; i < aList.size(); i++) {
System.out.printf("aList(%d) = %s bList(%d) = %s%n", i, aList.get(i), i, bList.get(i));
}
- iterate over the
aList
and check to see if corresponding elements satisfy thematch
criteria. - if so, add
a
to the results list. - then print the results.
List<A> results = new ArrayList<>();
int i = 0;
for (A a : aList) {
if (a.matches(bList.get(i++))) {
results.add(a);
}
}
System.out.println();
results.forEach(System.out::println);
output will be something like the following:
aList(0) = A{0, 1, 4, 1} bList(0) = A{0, 2, 2, 2}
aList(1) = A{1, 4, 0, 3} bList(1) = A{1, 2, 2, 3}
aList(2) = A{1, 1, 1, 4} bList(2) = A{1, 4, 2, 2}
aList(3) = A{0, 4, 3, 3} bList(3) = A{3, 2, 0, 2}
aList(4) = A{0, 4, 3, 1} bList(4) = A{1, 0, 4, 3}
aList(5) = A{3, 2, 3, 1} bList(5) = A{1, 2, 0, 3}
aList(6) = A{4, 3, 0, 2} bList(6) = A{3, 4, 0, 3}
aList(7) = A{4, 3, 2, 4} bList(7) = A{2, 1, 2, 2}
aList(8) = A{0, 3, 4, 3} bList(8) = A{3, 3, 4, 4}
aList(9) = A{1, 3, 3, 4} bList(9) = A{0, 1, 2, 0}
A{0, 1, 4, 1}
A{1, 4, 0, 3}
A{1, 1, 1, 4}
Updated Answer
- Here is one way. This won't work unless your lists are declared final or are effectively final.
final List<A> aList = List.of(new A(2, 20, 50, 60), new A(3, 25, 40, 60),
new A(4, 40, 10, 20));
final List<A> bList = List.of(new A(2, 10, 50, 60), new A(3, 25, 50, 60),
new A(4, 40, 10, 20));
List<A> results = IntStream.range(0, aList.size())
.filter(k -> aList.get(k).matches(bList.get(k)))
.mapToObj(aList::get).toList();
results.forEach(System.out::println);
prints
A{2, 20, 50, 60}
A{3, 25, 40, 60}
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论