合并两个大小不同的列表,在特定条件下合并为流 api
Merge Two List which have different size, In one with stream api on certain conditions
假设我有两个列表我想合并成一个
合并条件:
与 id
比较
Case 1 :
List 1 = [{id=1,name=null},{id=2,name=null},{id=3,name=c}]
List 2 = [{id=1,name=a},{id=2,name=b}]
合并后应该是[{id=1,name=a},{id=2,name=b},{id=3,name=c}]
Case 1 :
List 1 = [{id=1,name=null}]
List 2 = [{id=1,name=a},{id=2,name=b}]
合并后应该是[{id=1,name=a},{id=2,name=b}]
我的代码:
for (Object ObjofList1: list1) {
List<DummyObject> do = new ArrayLIst();
SomeObject sm = list2.stream()
.filter(list2object -> list2object.getId().equals(ObjofList1.getId()))
.findAny()
.orElse(ObjofList1);
do.add(dealerSalesTempObject);
}
如果 list2
中有更多元素,它工作正常,但如果 list1
中有更多元素,那么我们将无法合并,因为迭代较少。
我的问题是我不想看哪个更短或哪个更长,但最终所有对象都应该在一个列表中..
可以使用流合并这两个列表,然后使用distinct
,以去除重复元素,最后将其重新转换为list
:
Stream.concat(list1.stream(), list2.stream()).distinct().collect(Collectors.toList());
注意:您需要在您的DummyObject
中实现equals
和hashcode
,生成时需要删除重复的元素Set
.
您的案例的 HashCode 和 Equals(考虑评论中的信息):
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StockProcessData that = (StockProcessData) o;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
if (unContractedStock != null ? !unContractedStock.equals(that.unContractedStock) : that.unContractedStock != null)
return false;
return contractedStock != null ? contractedStock.equals(that.contractedStock) : that.contractedStock == null;
}
@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (unContractedStock != null ? unContractedStock.hashCode() : 0);
result = 31 * result + (contractedStock != null ? contractedStock.hashCode() : 0);
return result;
}
在这样的问题上引入 Stream 只会无缘无故地使事情变得更复杂。根据您的示例,您只想创建一个包含两个列表中的元素的集合。这样的事情将是实现它的最简单方法:
Set<Object> resultSet = new HashSet<>(list1);
result.addAll(list2);
List<Object> resultList = new ArrayList<>(result); // optionally if u want a List
此解决方案假定您的 class 实现了 equals()
和 hashcode()
方法。
您更新了您的问题并提到了将具有相同 ID 的对象合并为单个对象的用例。我能想到的方式是这样的:
List<DummyObject> list3 = new ArrayList<>(
Stream
.concat(list1.stream(), list2.stream())
.collect(Collectors.toMap(
DummyObject::getId,
Function.identity(),
(a, b) -> {
// here you can merge a and b
}
))
.values()
);
旧答案
不需要Stream
s,一个简单的SortedSet
就够了:
SortedSet<DummyObject> result = new TreeSet<>(Comparator.comparing(DummyObject::getId));
result.addAll(list1);
result.addAll(list2);
当你不想覆盖hashCode()
和equals()
方法时,可以使用SortedSet
。此外 result
按 id 排序。
如果您之后需要 List
,您可以轻松地将其转换回来:
List<DummyObject> list3 = new ArrayList<>(result);
但是使用 Set
可能更具声明性,因为它清楚地表明没有重复可用。
假设我有两个列表我想合并成一个
合并条件: 与 id
比较Case 1 :
List 1 = [{id=1,name=null},{id=2,name=null},{id=3,name=c}]
List 2 = [{id=1,name=a},{id=2,name=b}]
合并后应该是[{id=1,name=a},{id=2,name=b},{id=3,name=c}]
Case 1 :
List 1 = [{id=1,name=null}]
List 2 = [{id=1,name=a},{id=2,name=b}]
合并后应该是[{id=1,name=a},{id=2,name=b}]
我的代码:
for (Object ObjofList1: list1) {
List<DummyObject> do = new ArrayLIst();
SomeObject sm = list2.stream()
.filter(list2object -> list2object.getId().equals(ObjofList1.getId()))
.findAny()
.orElse(ObjofList1);
do.add(dealerSalesTempObject);
}
如果 list2
中有更多元素,它工作正常,但如果 list1
中有更多元素,那么我们将无法合并,因为迭代较少。
我的问题是我不想看哪个更短或哪个更长,但最终所有对象都应该在一个列表中..
可以使用流合并这两个列表,然后使用distinct
,以去除重复元素,最后将其重新转换为list
:
Stream.concat(list1.stream(), list2.stream()).distinct().collect(Collectors.toList());
注意:您需要在您的DummyObject
中实现equals
和hashcode
,生成时需要删除重复的元素Set
.
您的案例的 HashCode 和 Equals(考虑评论中的信息):
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StockProcessData that = (StockProcessData) o;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
if (unContractedStock != null ? !unContractedStock.equals(that.unContractedStock) : that.unContractedStock != null)
return false;
return contractedStock != null ? contractedStock.equals(that.contractedStock) : that.contractedStock == null;
}
@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (unContractedStock != null ? unContractedStock.hashCode() : 0);
result = 31 * result + (contractedStock != null ? contractedStock.hashCode() : 0);
return result;
}
在这样的问题上引入 Stream 只会无缘无故地使事情变得更复杂。根据您的示例,您只想创建一个包含两个列表中的元素的集合。这样的事情将是实现它的最简单方法:
Set<Object> resultSet = new HashSet<>(list1);
result.addAll(list2);
List<Object> resultList = new ArrayList<>(result); // optionally if u want a List
此解决方案假定您的 class 实现了 equals()
和 hashcode()
方法。
您更新了您的问题并提到了将具有相同 ID 的对象合并为单个对象的用例。我能想到的方式是这样的:
List<DummyObject> list3 = new ArrayList<>(
Stream
.concat(list1.stream(), list2.stream())
.collect(Collectors.toMap(
DummyObject::getId,
Function.identity(),
(a, b) -> {
// here you can merge a and b
}
))
.values()
);
旧答案
不需要Stream
s,一个简单的SortedSet
就够了:
SortedSet<DummyObject> result = new TreeSet<>(Comparator.comparing(DummyObject::getId));
result.addAll(list1);
result.addAll(list2);
当你不想覆盖hashCode()
和equals()
方法时,可以使用SortedSet
。此外 result
按 id 排序。
如果您之后需要 List
,您可以轻松地将其转换回来:
List<DummyObject> list3 = new ArrayList<>(result);
但是使用 Set
可能更具声明性,因为它清楚地表明没有重复可用。