![](/img/trans.png)
[英]Get List<String> and HashMap<String, Object> using Java 8 streams
[英]What is the right way to compare the List of HashMap in Java using streams
我想比较 Java 中的两个 HashMap 列表。我想了解一种使用 lambda 表达式而不是嵌套 for 循环来比较它们的方法。
两个 HashMap 列表:
样本数据:
[{ProductName=Prod1, Quantity=1.0, Perpetual=true},
{ProductName=Prod2, Quantity=1.0, Perpetual=false},
{ProductName=Prod3, Quantity=1.0, Perpetual=false}]
样本数据:
[{Perpetual=true, ProductName=Prod1, Quantity=1.0},
{Perpetual=true, ProductName=Prod2, Quantity=1.0},
{Perpetual=false, ProductName=Prod3, Quantity=2.0},
{Perpetual=false, ProductName=Prod4, Quantity=1.0},
{Perpetual=false, ProductName=Prod5, Quantity=1.0},
{Perpetual=false, ProductName=Prod6, Quantity=1.0}]
逻辑:我想遍历 productDetailsFromInputData 列表并获取每个 hashmap 的 ProductName 值,检查该值是否存在于 productDetailsFromApplication 列表中存在的任何哈希映射中。 如果不是,则将结果标记为失败。
如果 ProductName 作为值存在于 productDetailsFromApplication 列表的 hashmap 中的任何一个中,则从该 hashmap 中获取 Perpetual 和 Quantity 值,并将其与 productDetailsFromInputData 列表中的 hashmap 进行比较。
到目前为止,我已经尝试过以下方法:
for(HashMap<String,Object> inputProductHashMap : productDetailsFromInputData) {
String productName = inputProductHashMap.get("ProductName").toString();
String inputQuantity = inputProductHashMap.get("Quantity").toString();
String inputPerpetual = inputProductHashMap.get("Perpetual").toString();
LOGGER.info("Validating Product details for Product "+productName);
if(productDetailsFromApplication.stream().anyMatch(t->t.containsValue(productName))){
productDetailsFromApplication.stream()
.filter(p->p.containsValue(productName))
.findAny().ifPresent(p->
{
String AppQuantity = p.get("Quantity").toString();
String AppPerpetual = p.get("Perpetual").toString();
LOGGER.info("Found the Product details in SFDC matching with input data");
if(!inputQuantity.equalsIgnoreCase(AppQuantity)){
LOGGER.error("APP Quantity does not matches with Input Quantity for Product "+productName
+" App Quantity "+AppQuantity+" Input Quantity "+inputQuantity);
Assert.fail("Product Validation Failed for "+productName);
}
if(!inputPerpetual.equalsIgnoreCase(AppPerpetual)){
LOGGER.error("App Perpetual value does not matches with Input Perpetual value for Product "
+productName +" App Perpetual "+AppPerpetual+" Input perpetual "+inputPerpetual);
Assert.fail("Product Validation Failed "+productName);
}
});
}
else {
LOGGER.error("Did not find any matching Product Name with the given details in App");
return false;
}
}
我想了解是否还有办法删除第一个 for 循环。 由于我对使用 lambda 和流很陌生,我该如何优化它。
此外,我想知道一种方法,如果代码到达LOGGER.error
部分,我当前已在其中添加断言以标记失败,则返回 boolean 值。
如果现有的 Stack-overflow 问题涵盖了此问题的解决方案,请随时指导我。
从您的陈述中,我了解到您想返回false
而不是运行Assert.fail
。 仅使用 Streams 的方法是:
return !productDetailsFromInputData.stream().map(i ->
productDetailsFromApplication.stream().filter((a) -> a.get("ProductName").toString().equalsIgnoreCase(i.get("ProductName").toString())).findAny()
.map(a ->
!a.get("Perpetual").toString().equalsIgnoreCase(i.get("Perpetual").toString()) || !a.get("Quantity").toString().equalsIgnoreCase(i.get("Quantity").toString()))
.orElse(true)
).anyMatch(b -> b);
请注意,我将失败映射到true
,那是因为anyMatch
会寻找任何真值。 然后我们用!
在回报中。
如果你想保持 LOGGER 的冗长,你可以这样做:
return !productDetailsFromInputData.stream().map(i ->
productDetailsFromApplication.stream().filter((a) -> a.get("ProductName").toString().equalsIgnoreCase(i.get("ProductName").toString())).findAny()
.map(a -> {
if(!a.get("Quantity").toString().equalsIgnoreCase(i.get("Quantity").toString())) {
LOGGER.error("APP Quantity does not matches with Input Quantity for Product "+i.get("ProductName").toString()
+" App Quantity "+a.get("Quantity").toString()+" Input Quantity "+i.get("Quantity").toString());
return true;
}
if(!a.get("Perpetual").toString().equalsIgnoreCase(i.get("Perpetual").toString())) {
LOGGER.error("App Perpetual value does not matches with Input Perpetual value for Product "
+i.get("ProductName").toString() +" App Perpetual "+a.get("Perpetual").toString()+" Input perpetual "+i.get("Perpetual").toString());
return true;
}
return false;
})
.orElseGet(() -> {
LOGGER.error("Did not find any matching Product Name with the given details in App");
return true;
})
).anyMatch(b -> b);
但是,我建议不要只使用 Streams 并首先将productDetailsFromApplication
转换为 Map,这样可以更快地找到匹配项:
Map<String, Map<String, Object>> mapFromApplication = productDetailsFromApplication.stream().collect(Collectors.toMap(e -> e.get("ProductName").toString(), Function.identity()));
return !productDetailsFromInputData.stream().map(i ->
Optional.ofNullable(mapFromApplication.get(i.get("ProductName").toString()))
.map(a -> {
if(!a.get("Quantity").toString().equalsIgnoreCase(i.get("Quantity").toString())) {
LOGGER.error("APP Quantity does not matches with Input Quantity for Product "+i.get("ProductName").toString()
+" App Quantity "+a.get("Quantity").toString()+" Input Quantity "+i.get("Quantity").toString());
return true;
}
if(!a.get("Perpetual").toString().equalsIgnoreCase(i.get("Perpetual").toString())) {
LOGGER.error("App Perpetual value does not matches with Input Perpetual value for Product "
+i.get("ProductName").toString() +" App Perpetual "+a.get("Perpetual").toString()+" Input perpetual "+i.get("Perpetual").toString());
return true;
}
return false;
})
.orElseGet(() -> {
LOGGER.error("Did not find any matching Product Name with the given details in App");
return true;
})
).anyMatch(b -> b);
这将在第一次失败时停止,而不计算所有失败。 如果您可以从计算失败次数和/或记录所有失败次数中获益,则可以使用.filter(b -> b).count()
而不是.anyMatch(b -> b)
。
long count = productDetailsFromInputData.stream().map(i ->
...
.filter(b -> b).count();
if(count>0) {
LOGGER.error(count+" failures.");
return false;
} else {
return true;
}
编辑:您实际上可以将anyMatch
语句进一步向上移动以替换第一个map
,但是将它放在底部可以让您轻松地将其更改为其他用途,例如需要时的count
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.