无法应用 Merge 函数转换为在 Stream 输出上获取 Set
Unable to apply Merge function to convert to get Set on a Stream output
这是一个示例源数据结构,用于简化我的场景的问题案例数据。
此地图对不同的代码有重复的描述。
Map<Integer, String> descriptionsByCode = new HashMap();
descriptionsByCode.put(1, "description 1");
descriptionsByCode.put(2, "description 2");
descriptionsByCode.put(4, "description 3");
descriptionsByCode.put(5, "description 4");
descriptionsByCode.put(6, "description 5");
descriptionsByCode.put(7, "description 5");
descriptionsByCode.put(8, "description 5");
descriptionsByCode.put(9, "description 2");
descriptionsByCode.put(10, "description 2");
descriptionsByCode.put(11, "description 3");
descriptionsByCode.put(12, "description 4");
descriptionsByCode.put(13, "description 1");
descriptionsByCode.put(14, "description 6");
descriptionsByCode.put(15, "description 8");
我也有一个复杂的业务对象,但为了简单起见,我们假设有一个只有 2 个字段的对象。
@Data
@AllArgsConstructor
class StatusCounts {
private String description;
private Map<Integer, Integer> someIemCountByStatusCode; //defaults to zero for our example
}
如果,我想要一个 StatusCount
对象的地图,按描述。
我可以轻松拥有它。下面是一个工作代码,添加到这里是为了集中解决此后提到的主要问题
Map<String, StatusCounts> statusCountsByDescription
= descriptionsByCode
.entrySet()
.stream()
.collect(Collectors.toMap(
e -> e.getValue(), //key function
e -> new StatusCounts(e.getValue(), //value function
Collections.singletonMap(e.getKey(), 0)),
(e, v) -> // merge function for collision
{ // is there a better way to write below code ?
Map m = new HashMap();
m.putAll(e.getItemCountByStatusCode());
m.putAll(v.getItemCountByStatusCode());
e.setItemCountByStatusCode(m);
return e;
}
));
以上代码不干净,但运行良好。
我真正想要的是一个 Set 而不是 Map
我无法在 reduce
或 collect
函数中找到一种方法来为 collision detection
提供处理(就像合并函数在 Collectors.toMap
的情况下所做的那样) ).
reduce 或 collect 中的组合器功能对碰撞不起作用。
Collectors.toSet
甚至不接受任何参数。
所以我虽然可以在 reduce
的情况下在 accumulator
中或在 collect
的情况下在或 Biconsumer
中编写碰撞检测处理。所以我在下面尝试使用 collect
& BiConsumer
但是这个是不可编译的reduce
Set<StatusCounts> statusCounts
= descriptionsByCode
.entrySet()
.stream()
.collect(() -> new HashSet<StatusCounts>(),
(set, entry) -> {
Optional<StatusCounts> statusCount
= findStatusCountWithSameDescription(set, entry.getValue());
if (statusCount.isPresent()) {
statusCount.get()
.getItemCountByStatusCode()
.put(entry.getKey(), 0);
} else {
set.add(new StatusCounts(
entry.getValue(),
Collections.singletonMap(entry.getKey(), 0)));
}
return set;
}
);
private static Optional<StatusCounts> findStatusCountWithSameDescription
(HashSet<StatusCounts> set, String description) {
return set.stream()
.filter(e -> e.getDescription()
.equalsIgnoreCase(description))
.findFirst();
}
这是编译错误
Cannot resolve method 'collect(<lambda expression>, <lambda expression>)'
您可以使用 Collectors.groupingBy
来解决这个问题:
Map<String, Set<Integer>> map
= descMap.entrySet()
.stream()
.collect(Collectors.groupingBy(Entry::getValue,
Collectors.mapping(Entry::getKey, Collectors.toSet())));
这里会生成一张以描述为key的地图。 Collectors.mapping
将每个条目映射到状态代码,然后将它们组合成一个 Set
我认为 Set<Integer>
而不是 Map<Integer, Integer>
在 StatusCounts
class 中就足够了。这是因为从代码来看,您似乎只想知道描述下的不同代码。在这种情况下,您可以尝试以下操作:
return map.entrySet()
.stream()
.map(entry -> new StatusCounts(entry.getKey(), entry.getValue()))
.collect(Collectors.toSet());
更新
如果不允许更改现有的 StatusCounts
class,那么您可以尝试以下操作:
Map<String, Map<Integer, Integer>> tempMap
= descMap.entrySet()
.stream()
.collect(Collectors.groupingBy(Entry::getValue,
Collectors.mapping(Entry::getKey, Collectors.toMap(Function.identity(), v -> 0))));
// You may combine the below code with above instead of using a tempMap.
// I have separated it for simplicity
Set<StatusCounts> result
= tempMap.entrySet()
.stream()
.map(entry -> new StatusCounts(entry.getKey(), entry.getValue()))
.collect(Collectors.toSet());
这是一个示例源数据结构,用于简化我的场景的问题案例数据。 此地图对不同的代码有重复的描述。
Map<Integer, String> descriptionsByCode = new HashMap();
descriptionsByCode.put(1, "description 1");
descriptionsByCode.put(2, "description 2");
descriptionsByCode.put(4, "description 3");
descriptionsByCode.put(5, "description 4");
descriptionsByCode.put(6, "description 5");
descriptionsByCode.put(7, "description 5");
descriptionsByCode.put(8, "description 5");
descriptionsByCode.put(9, "description 2");
descriptionsByCode.put(10, "description 2");
descriptionsByCode.put(11, "description 3");
descriptionsByCode.put(12, "description 4");
descriptionsByCode.put(13, "description 1");
descriptionsByCode.put(14, "description 6");
descriptionsByCode.put(15, "description 8");
我也有一个复杂的业务对象,但为了简单起见,我们假设有一个只有 2 个字段的对象。
@Data
@AllArgsConstructor
class StatusCounts {
private String description;
private Map<Integer, Integer> someIemCountByStatusCode; //defaults to zero for our example
}
如果,我想要一个 StatusCount
对象的地图,按描述。
我可以轻松拥有它。下面是一个工作代码,添加到这里是为了集中解决此后提到的主要问题
Map<String, StatusCounts> statusCountsByDescription
= descriptionsByCode
.entrySet()
.stream()
.collect(Collectors.toMap(
e -> e.getValue(), //key function
e -> new StatusCounts(e.getValue(), //value function
Collections.singletonMap(e.getKey(), 0)),
(e, v) -> // merge function for collision
{ // is there a better way to write below code ?
Map m = new HashMap();
m.putAll(e.getItemCountByStatusCode());
m.putAll(v.getItemCountByStatusCode());
e.setItemCountByStatusCode(m);
return e;
}
));
以上代码不干净,但运行良好。 我真正想要的是一个 Set 而不是 Map
我无法在 reduce
或 collect
函数中找到一种方法来为 collision detection
提供处理(就像合并函数在 Collectors.toMap
的情况下所做的那样) ).
reduce 或 collect 中的组合器功能对碰撞不起作用。
Collectors.toSet
甚至不接受任何参数。
所以我虽然可以在 reduce
的情况下在 accumulator
中或在 collect
的情况下在或 Biconsumer
中编写碰撞检测处理。所以我在下面尝试使用 collect
& BiConsumer
但是这个是不可编译的reduce
Set<StatusCounts> statusCounts
= descriptionsByCode
.entrySet()
.stream()
.collect(() -> new HashSet<StatusCounts>(),
(set, entry) -> {
Optional<StatusCounts> statusCount
= findStatusCountWithSameDescription(set, entry.getValue());
if (statusCount.isPresent()) {
statusCount.get()
.getItemCountByStatusCode()
.put(entry.getKey(), 0);
} else {
set.add(new StatusCounts(
entry.getValue(),
Collections.singletonMap(entry.getKey(), 0)));
}
return set;
}
);
private static Optional<StatusCounts> findStatusCountWithSameDescription
(HashSet<StatusCounts> set, String description) {
return set.stream()
.filter(e -> e.getDescription()
.equalsIgnoreCase(description))
.findFirst();
}
这是编译错误
Cannot resolve method 'collect(<lambda expression>, <lambda expression>)'
您可以使用 Collectors.groupingBy
来解决这个问题:
Map<String, Set<Integer>> map
= descMap.entrySet()
.stream()
.collect(Collectors.groupingBy(Entry::getValue,
Collectors.mapping(Entry::getKey, Collectors.toSet())));
这里会生成一张以描述为key的地图。 Collectors.mapping
将每个条目映射到状态代码,然后将它们组合成一个 Set
我认为 Set<Integer>
而不是 Map<Integer, Integer>
在 StatusCounts
class 中就足够了。这是因为从代码来看,您似乎只想知道描述下的不同代码。在这种情况下,您可以尝试以下操作:
return map.entrySet()
.stream()
.map(entry -> new StatusCounts(entry.getKey(), entry.getValue()))
.collect(Collectors.toSet());
更新
如果不允许更改现有的 StatusCounts
class,那么您可以尝试以下操作:
Map<String, Map<Integer, Integer>> tempMap
= descMap.entrySet()
.stream()
.collect(Collectors.groupingBy(Entry::getValue,
Collectors.mapping(Entry::getKey, Collectors.toMap(Function.identity(), v -> 0))));
// You may combine the below code with above instead of using a tempMap.
// I have separated it for simplicity
Set<StatusCounts> result
= tempMap.entrySet()
.stream()
.map(entry -> new StatusCounts(entry.getKey(), entry.getValue()))
.collect(Collectors.toSet());