首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >将两个对象列表合并到在Java8中作为不同对象的Map中

将两个对象列表合并到在Java8中作为不同对象的Map中
EN

Stack Overflow用户
提问于 2018-08-20 21:02:26
回答 4查看 1.9K关注 0票数 6

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

代码语言:javascript
复制
public class MyInfoObject {
  private Long id;
  private String signature;

  public MyInfoObject(Long id, String signature) {
      super();
      this.id = id;
      this.signature = signature;
  }
}

我想创建这两个列表的映射,这样列表A的所有ids和列表B的所有ids都具有相同的签名,从而创建一个类型为"BucketOfAandB“的存储桶:

代码语言:javascript
复制
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;
  }
 }

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

例如,我的输入是:

代码语言:javascript
复制
    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"));

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

代码语言:javascript
复制
{
    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]],
}

我想用java8的Streams来实现。

我想出的一种方法是:

aList创建Map<String, List<Long>>,比方说 bList和create resultantMap<String, BucketOfAandB> by

  • 2a。将具有相同签名的aBuckets中的列表设置为resultant,并将其从aBuckets
  • 2b.中删除向所需签名bucket

添加bList元素

  1. 迭代aBuckets的所有剩余元素并将它们添加到resultant

我想知道使用Java8的Streams实现这一点的更好方法。

提前感谢!

编辑:我试着使用流,但对实现不是很满意。以下是我的逻辑:

代码语言:javascript
复制
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);
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2018-08-20 21:30:00

如果你将getters添加到MyInfoObject,并让BucketOfAandB惰性地初始化它的列表(即没有构造函数),如下所示:

代码语言:javascript
复制
public class BucketOfAandB {
    private List<Long> aIds;
    private List<Long> bIds;
    public void addAId(Long id) {
        if (aIds == null) {
            aIds = new ArrayList<>();
        }
        aIds.add(id);
    }
    public void addBId(Long id) {
        if (bIds == null) {
            bIds = new ArrayList<>();
        }
        bIds.add(id);
    }
}

你可以只用3行代码就可以做到,同时保留了你意图的语义:

代码语言:javascript
复制
Map<String, BucketOfAandB> map = new HashMap<>();
aList.forEach(o -> map.computeIfAbsent(o.getSignature(), s -> new BucketOfAandB())
  .addAId(o.getId()));
bList.forEach(o -> map.computeIfAbsent(o.getSignature(), s -> new BucketOfAandB())
  .addBId(o.getId()));

如果你使用并行流,添加synchronize方法,这实际上不会增加性能影响,因为它只是一个潜在的桶上的冲突。

票数 2
EN

Stack Overflow用户

发布于 2018-08-20 21:19:05

这样如何:

代码语言:javascript
复制
    Map<String, List<Long>> mapA = aList.stream()
            .collect(Collectors.groupingBy(
                    MyInfoObject::getSignature,
                    Collectors.mapping(MyInfoObject::getId, Collectors.toList())));

    Map<String, List<Long>> mapB = bList.stream()
            .collect(Collectors.groupingBy(
                    MyInfoObject::getSignature,
                    Collectors.mapping(MyInfoObject::getId, Collectors.toList())));

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

    Set<String> allKeys = new HashSet<>();
    allKeys.addAll(mapA.keySet());
    allKeys.addAll(mapB.keySet());

    allKeys.forEach(x -> overAll.put(x, new BucketOfAandB(mapA.get(x), mapB.get(x))));

但这里假设listA中的每个密钥都会出现在listB

票数 3
EN

Stack Overflow用户

发布于 2018-08-20 21:29:47

你可以这样写:

代码语言:javascript
复制
Function<List<MyInfoObject>, Map<String, List<Long>>> toLongMap =
      list -> list.stream()
                  .collect(groupingBy(MyInfoObject::getSignature,
                                      mapping(MyInfoObject::getId, toList())));

Map<String, List<Long>> aMap = toLongMap.apply(aList);
Map<String, List<Long>> bMap = toLongMap.apply(bList);

Map<String, BucketOfAandB> finalMap = new HashMap<>();
aMap.forEach((sign, listA) -> {
    finalMap.put(sign, new BucketOfAandB(listA, bMap.get(sign)));
});
bMap.forEach((sign, listB) -> {
    finalMap.putIfAbsent(sign, new BucketOfAandB(null, listB));
});
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51931371

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档