当前位置: 首页 > 知识库问答 >
问题:

将两个对象列表合并到具有值的地图中,作为Java 8中的不同对象

卢俊发
2023-03-14

我有两个相同类型“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;
  }
}

我想创建这两个列表的映射,以便列表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;
  }
 }

因此,我的输出将是map ,其中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"));

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

{
    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]],
}

我想用Java 8的流来做这件事。

我想出的一个办法是:

  • 列表创建映射 > ,say abuckets
  • 迭代bList并创建结果映射 依据
    • 2A。将具有相同签名的aBuckets的列表设置为结果列表,将其从aBuckets
    • 中删除
    • 2b。将blist元素添加到所需签名桶

    我想知道一个更好的方法来实现这个使用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);
    

共有1个答案

淳于乐池
2023-03-14

如果您将getter添加到MyInfoObject中,并使BucketOfaandb惰性初始化其列表(即没有构造函数),如下所示:

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

您可以在保留您意图的语义的情况下,只需三行即可完成此操作:

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将添加方法,这实际上不会增加性能损失,因为它只是桶上的潜在冲突。

 类似资料:
  • 我有一个Java类,它有20个属性及其相应的getter和setter。还有两个对象列表:和。 使用Java 8: 但是我必须在哪个地方指定属性呢?是否应该重写和方法?

  • 首先,我的问题类似于这个已经回答过的问题,在Java中,将两个arrayList合并成一个新的arrayList,没有重复项,并且顺序正确。 然而,这里的不同之处在于,我尝试将两个列表合并在一起,而不仅仅是一个字符串。我的意图是合并以下类型的两个对象(为了简化,我从示例中去掉了不必要的信息): 所以我得到了一个新的项目,它有一个总结计数。这将消除不需要的重复,因为这些对象上的uniqueKey是相

  • 问题内容: 我有一个带有20个属性的Java类及其相应的getter和setters。我也有两个对象列表:和。 现在,我想合并两个列表,并避免基于和的重复对象。 使用Java 8: 但是我必须在哪里指定属性?我应该重写和方法吗? 问题答案: 如果要实现and ,则 在 类 内部 进行操作。在该类中添加类似的方法 如果您这样做了,在上调用将自动执行正确的操作。 如果您不想(或无法)更改类,则没有平等

  • 如何将一个流中的对象同时添加到两个不同的列表中 目前我正在做 要将流中的对象添加到linkedlist“resourceMemory”中,我还想同时将相同的对象添加到另一个列表中,但我找不到它的语法。是否可能,或者每个列表需要两份代码副本?

  • 问题内容: 我想将地图转换为: 至 结果列表是所有列表值的合并。 问题答案: 你可以有 这将检索映射的值,然后将每个列表平面映射到由其元素形成的Stream中,并将结果收集到列表中。 另一种选择是,不对每个列表进行平面映射,从而可能会提高性能,而无需对每个列表进行平面映射,则可以通过调用每个累加的结果来直接收集(由返回)。

  • null 在Java8流中如何做到这一点? 我开始把它们放进桶里(见下文),但不确定从这里去哪里: