将两个对象列表合并到Map中,将值作为java 8中的不同对象

Mak*_*Mak 6 java collections lambda java-8 java-stream

我有两个相同类型"MyInfoObject"的列表(比如A和B),这样:

public class MyInfoObject {
  private Long id;
  private String signature;

  public MyInfoObject(Long id, String signature) {
      super();
      this.id = id;
      this.signature = signature;
  }
}
Run Code Online (Sandbox Code Playgroud)

我想创建这两个列表的Map,以便列表A的所有ID和具有相同签名的列表B的所有ID创建一个类型为"BucketOfAandB"的桶:

public class BucketOfAandB {
  private List<Long> aIds ;
  private List<Long> bIds ;

  public BucketOfAandB(List<Long> aIds, List<Long> bIds) {
    super();
    this.aIds = aIds;
    this.bIds = bIds;
  }
 }
Run Code Online (Sandbox Code Playgroud)

所以,我的输出将是Map<String, BucketOfAandB>,其中key是签名

我的输入是:

    List<MyInfoObject> aList = new ArrayList<>();
    aList.add(new MyInfoObject(1l, "a"));
    aList.add(new MyInfoObject(2l, "d"));
    aList.add(new MyInfoObject(3l, "b"));
    aList.add(new MyInfoObject(4l, "a"));
    aList.add(new MyInfoObject(5l, "a"));
    aList.add(new MyInfoObject(6l, "c"));
    aList.add(new MyInfoObject(7l, "a"));
    aList.add(new MyInfoObject(8l, "c"));
    aList.add(new MyInfoObject(9l, "b"));
    aList.add(new MyInfoObject(10l, "d"));

    List<MyInfoObject> bList = new ArrayList<>();
    bList.add(new MyInfoObject(11l, "a"));
    bList.add(new MyInfoObject(21l, "e"));
    bList.add(new MyInfoObject(31l, "b"));
    bList.add(new MyInfoObject(41l, "a"));
    bList.add(new MyInfoObject(51l, "a"));
    bList.add(new MyInfoObject(61l, "c"));
    bList.add(new MyInfoObject(71l, "a"));
    bList.add(new MyInfoObject(81l, "c"));
    bList.add(new MyInfoObject(91l, "b"));
    bList.add(new MyInfoObject(101l, "e"));
Run Code Online (Sandbox Code Playgroud)

在这种情况下我的输出将是:

{
    a= BucketOfAandB[aIds=[1, 4, 5, 7], bIds=[11, 41, 51, 71]],
    b= BucketOfAandB[aIds=[3, 9], bIds=[31, 91]],
    c= BucketOfAandB[aIds=[6, 8], bIds=[61, 81]],
    d= BucketOfAandB[aIds=[2, 10], bIds=null],
    e= BucketOfAandB[aIds=null, bIds=[21, 101]],
}
Run Code Online (Sandbox Code Playgroud)

我想用java 8的Streams来做.

我想到的一种方法是:

  1. Map<String, List<Long>>aListaBuckets 创建起来
  2. 迭代bList创造resultant Map<String, BucketOfAandB>
    • 2A.将具有相同签名的aBuckets中的List设置为结果,将其从中删除aBuckets
    • 2B.添加bList所需签名桶的元素
  3. 迭代所有剩余的元素aBuckets并将它们添加到resultant

我想知道使用Streams of Java 8实现这一点的更好方法.

提前致谢!

编辑:我尝试使用流但不是很满意实现.以下是我的逻辑:

Map<String, BucketOfAandB> resultmap  = new HashMap<>();

    // get ids from aList grouped by signature
    Map<String, List<Long>> aBuckets = aList.stream().collect(Collectors.groupingBy(MyInfoObject::getSignature,
            Collectors.mapping(MyInfoObject::getId, Collectors.toList())));

    // iterate bList and add it to bucket of its signature
    bList.forEach(reviewInfo -> {
        BucketOfAandB bucket = resultmap.get(reviewInfo.getSignature());

        if(null ==  bucket) {
            bucket = new BucketOfAandB();
            resultmap.put(reviewInfo.getSignature(), bucket);

            List<Long> sourceReviewBucket =  aBuckets.remove(reviewInfo.getSignature());
            if(null !=sourceReviewBucket) {
                bucket.setaIds(sourceReviewBucket);
            }
        }
        bucket.addToB(reviewInfo.getId());
    });

    Map<String, BucketOfAandB> result = aBuckets.entrySet().stream()
            .collect(Collectors.toMap(Map.Entry::getKey, e -> new BucketOfAandB(e.getValue(), null)));

    resultmap.putAll(result);
Run Code Online (Sandbox Code Playgroud)

Boh*_*ian 2

如果将 getter 添加到MyInfoObject,并BucketOfAandB延迟初始化其列表(即没有构造函数),如下所示:

\n\n
public class BucketOfAandB {\n    private List<Long> aIds;\n    private List<Long> bIds;\n    public void addAId(Long id) {\n        if (aIds == null) {\n            aIds = new ArrayList<>();\n        }\n        aIds.add(id);\n    }\n    public void addBId(Long id) {\n        if (bIds == null) {\n            bIds = new ArrayList<>();\n        }\n        bIds.add(id);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

您只需 3 行即可完成,同时保留您意图的语义:

\n\n
Map<String, BucketOfAandB> map = new HashMap<>();\naList.forEach(o -> map.computeIfAbsent(o.getSignature(), s -> new BucketOfAandB())\n  .addAId(o.getId()));\nbList.forEach(o -> map.computeIfAbsent(o.getSignature(), s -> new BucketOfAandB())\n  .addBId(o.getId()));\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果您\xe2\x80\x99 使用并行流,synchronize则添加方法实际上不会增加​​任何性能影响,因为\xe2\x80\x99 仅在存储桶上产生潜在的冲突。

\n