【问题标题】:How to merge two lists after comparing using java streams API使用java流API比较后如何合并两个列表
【发布时间】:2021-08-19 16:03:05
【问题描述】:

我有两个相同类型的列表: 框 1 和框 2:

"boxes1": [{
        "boxId": "ABC",
        "ele": [{
                "eleId": "8040",
                "chars": [{
                        "no": "123",
                        "qty": 2
                    }
                ]
            }
        ]
    }, {
        "boxId": "XYZ",
        "ele": [{
                "eleId": "1212",
                "chars": [{
                        "no": "456",
                        "qty": 3
                    }
                ]
            }
        ]
    }
]

"boxes2": [{
        "boxId": "ABC",
        "ele": [{
                "eleId": "8040",
                "chars": [{
                        "no": "123",
                        "qty": 6
                    }
                ]
            }, {
                "eleId": "4560",
                "chars": [{
                        "no": "012",
                        "qty": 3
                    }
                ]
            }
        ]
    }, {
        "boxId": "PQR",
        "ele": [{
                "eleId": "1111",
                "chars": [{
                        "no": "456",
                        "qty": 8
                    }
                ]
            }
        ]
    }
]

我想检查 boxes1 中的任何 boxId 是否与 boxes2 中的 boxId 匹配,然后我想将box1的一个公共元素eleIdchars添加到box2中,这样组合后的结果是这样的:

"box2": [{
        "boxId": "ABC",
        "ele": [{
                "eleId": "8040",
                "chars": [{
                        "no": "123",
                        "qty": 6
                    },
                    {
                        "no": "123",
                        "qty": 2
                    }
                ]
            },.....................

如果 Boxes1 中有任何 boxId 不存在于 Boxes2 我想将该框添加到 盒子2。所以最后它应该看起来像:

"box2": [{
        "boxId": "ABC",
        "ele": [{
                "eleId": "8040",
                "chars": [{
                        "no": "123",
                        "qty": 6
                    }, {
                        "no": "123",
                        "qty": 2
                    }
                ]
            }, {
                "eleId": "4560",
                "chars": [{
                        "no": "012",
                        "qty": 3
                    }
                ]
            }
        ]
    }, {
        "boxId": "PQR",
        "ele": [{
                "eleId": "1111",
                "chars": [{
                        "no": "456",
                        "qty": 8
                    }
                ]
            }
        ]
    }, {
        "boxId": "XYZ",
        "ele": [{
                "eleId": "1212",
                "chars": [{
                        "no": "456",
                        "qty": 3
                    }
                ]
            }
        ]
    }
]

我是 Stream 的新手,所以尝试使用旧方法,但它有问题:

boxes2.forEach(box2 -> {
            boxes1.forEach(box1 -> {
                if (box1.getBoxId().equals(box2.getBoxId())) {
                    box2.getEle().forEach(ele1 -> {
                        box1.getEle().forEach(ele2 -> {
                            if (ele1.getEleId().equals(ele2.getEleId())) {
                                ele1.chars().addAll(ele2.chars());
                            }
                        });
                    });
                } else {
                    boxes2.add(box1);
                }
            });
        });

【问题讨论】:

  • 到目前为止你有什么尝试?
  • 添加到问题中,谢谢。
  • 该代码不可读且非常嵌套。老实说,我不确定你想用它来实现什么。另外,您的 JSON 列表在代码中是如何表示的?
  • 是的,代码有问题,但你明白这里的问题吗?
  • 这是我喜欢 javascript 的时候之一。这东西在javascript中真的很简单

标签: java java-8 java-stream backend


【解决方案1】:

使用Streams 对您的情况没有多大帮助。我建议使用 POIC(普通的旧命令式代码)。

伪码算法:

for ( box1 of boxes1 ) {
  var box1Id = box.boxId;
  if ( boxes2.containsBoxId(box1Id) ) {
    var box2 = boxes2.getBoxById(boxId);
    
    for ( ele1 of box1.ele ) {
      var ele1Id = ele1.eleId;
      if ( box2.containsEleId(ele1Id) ) {
        var ele2 = box2.getEleById(ele1Id);

        ele2.addToChars(ele1.chars);
      }
    }
  
  } else {
    // if boxes2 doesn't contain box1Id
    boxes2.addBox(box1);
  }
}

对于Streams,我唯一会考虑的是“查找匹配的元素并添加字符”部分。但对于大型收藏品来说,这会变慢。

var box1Id = ...
var box1ele = ...
boxes2.stream()
  .filter(b -> b.boxId.equals(box1Id))
  .flatMap(b -> b.ele.stream())
  .filter(e -> e.eleId.equals(box1ele))
  .forEach(e -> e.addChars(box1ele.chars)

您当然也可以使用Streams 进行box1 迭代。但这会导致一些非常丑陋和不可读的代码。 (编辑:就像你的示例代码:不好。)

您可以做些什么:将相关数据放在Map 中,以便在没有所有这些循环的情况下更快、更轻松地访问。

【讨论】:

    【解决方案2】:

    另一种解决方案是这样的:

    List<Box> boxResult = Stream.concat(boxes1.stream(), boxes2.stream())
                .collect(toMap(Box::getBoxId, 
                               v-> new ArrayList<>(v.getEle()),
                               YOUR_CLASS::mergeEle))
                .entrySet().stream()
                .map(entry -> new Box(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
    

    mergeEle方法:

    private static List<Ele> mergeEle(List<Ele> l1, List<Ele> l2) {
        return Stream.concat(l1.stream(), l2.stream())
                .collect(toMap(Ele::getEleId,
                               v -> new ArrayList<>(v.getChars()),
                               YOUR_CLASS::mergeChar))
                .entrySet().stream()
                .map(e -> new Ele(e.getKey(), e.getValue()))
                .collect(Collectors.toList());
    }
    

    mergeChar:

    private  List<Char> mergeChar(List<Char> c1, List<Char> c2) {
        c1.addAll(c2);
        return c1;
    }
    

    【讨论】:

      猜你喜欢
      • 2019-04-08
      • 1970-01-01
      • 2011-02-15
      • 1970-01-01
      • 2018-05-07
      • 2016-05-05
      • 2017-08-10
      • 1970-01-01
      相关资源
      最近更新 更多