Merge Two List which have different size, In one with stream api on certain conditions

huangapple go评论70阅读模式
英文:

Merge Two List which have different size, In one with stream api on certain conditions

问题

假设我有两个列表我想要将它们合并成一个

**合并条件
按照 id 进行比较**

    情况 1
    列表 1 = [{id=1,name=null},{id=2,name=null},{id=3,name=c}]
    列表 2 = [{id=1,name=a},{id=2,name=b}]

合并后应该得到 [{id=1,name=a},{id=2,name=b},{id=3,name=c}]

  
    情况 2
    列表 1 = [{id=1,name=null}]
    列表 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` 中的元素更多由于迭代次数较少我们将无法合并

我的问题是我不想知道哪个列表较短或较长但最终所有对象都应该在一个列表中
英文:

Suppose I have two list which i want to get merged into one

Merge Condition :
compare with 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}]

After the merge, it should be [{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}]

After the merge, it should be [{id=1,name=a},{id=2,name=b}]

My code:

 for (Object ObjofList1: list1) {
             List&lt;DummyObject&gt; do = new ArrayLIst();
            SomeObject sm = list2.stream()
                    .filter(list2object -&gt; list2object.getId().equals(ObjofList1.getId()))
                    .findAny()
                    .orElse(ObjofList1);
                          do.add(dealerSalesTempObject);
          
        }

It is working fine if list2 has more elements in it, but if list1 has more element then we won't be able to merge because of less iteration.

My question is i don't want to see which one is shorter or longer but at last all objects should be in one list..

答案1

得分: 4

介绍流(Stream)到这样的问题只会使事情变得更复杂,没有真正的理由。根据你的示例,你只想要创建一个包含两个列表元素的集合(Set)。以下是实现这一目标最简单的方法:

Set<Object> resultSet = new HashSet<>(list1);
resultSet.addAll(list2);
List<Object> resultList = new ArrayList<>(resultSet); // 可选,如果你想要一个列表(List)

这个解决方案假设你的类实现了 equals()hashcode() 方法。

英文:

Introducing Stream to such problem just makes things more complicated for no real reason. Based on your example you just want to create a Set containing elements from both Lists. Something like this would be the easiest way to achieve it:

Set&lt;Object&gt; resultSet = new HashSet&lt;&gt;(list1);
result.addAll(list2);
List&lt;Object&gt; resultList = new ArrayList&lt;&gt;(result); // optionally if u want a List

This solution assumes that your class implements equals() and hashcode() methods.

答案2

得分: 2

你可以使用流(streams)合并这两个列表,然后使用 distinct 方法来删除重复元素,最后将其重新转换为 list

Stream.concat(list1.stream(), list2.stream()).distinct().collect(Collectors.toList());

注意: 你需要在你的 DummyObject 中实现 equalshashcode 方法,以便在生成 Set 时删除重复元素。

针对你的情况,考虑到注释中的信息,这是 equalshashcode 的实现:

@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;
}
英文:

You can merge these two lists using streams, and then use distinct, in order to remove duplicate elements, and finally reconvert it to a list:

Stream.concat(list1.stream(), list2.stream()).distinct().collect(Collectors.toList());

NOTE: you need to implement equals and hashcode in your DummyObject, it's required to remove the duplicated elements when generating the Set.

HashCode and Equals for your case (Considering the infos in the comments):

@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;
}

答案3

得分: 2

你已更新问题,并提到将具有相同 id 的对象合并为单个对象的用例。我能想到的方法类似于这样:

List<DummyObject> list3 = new ArrayList<>(
    Stream
        .concat(list1.stream(), list2.stream())
        .collect(Collectors.toMap(
            DummyObject::getId, 
            Function.identity(), 
            (a, b) -> {
                 // 在这里你可以合并 a 和 b
            }
         ))
         .values()
    );

旧回答

不需要使用 Stream,一个简单的 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 可能更具有声明性,因为它明确表示没有重复项可用。

英文:

You have updated your question and mentioned the use case of merging objects with the same id into a single object. The way I can think of would be something like this:

List&lt;DummyObject&gt; list3 = new ArrayList&lt;&gt;(
    Stream
        .concat(list1.stream(), list2.stream())
        .collect(Collectors.toMap(
            DummyObject::getId, 
            Function.identity(), 
            (a, b) -&gt; {
                 // here you can merge a and b
            }
         ))
         .values()
    );

Old answer

No need for Streams, a simple SortedSet is enough:

SortedSet&lt;DummyObject&gt; result = new TreeSet&lt;&gt;(Comparator.comparing(DummyObject::getId));
result.addAll(list1);
result.addAll(list2);

The SortedSet can be used when you don't want to override the hashCode() and equals() methods. Additionally the result is sorted by id.

If you need a List afterwards you can convert it easily back:

List&lt;DummyObject&gt; list3 = new ArrayList&lt;&gt;(result);

But using a Set may be more declarative, as it clearly indicates that no duplicates are available.

huangapple
  • 本文由 发表于 2020年9月21日 16:58:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/63989109.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定