使用 Stream IPA 将一对元素映射为一个元素
Mapping pair of elements into one with Stream IPA
所以我想知道以下问题的最佳解决方案是什么:
我在 java 集合 ex
中有一个项目列表(自定义 class)
List<Item> itemList = ... item1,item2,item3 etc
然而,集合中的每个项目在集合中也有对应的逻辑对(因此这对不一定按集合中的索引彼此跟随)
我有一个像
这样的辅助方法
Item calculateCorrectItem(Item item1, Item item2)
哪个可以 return 基于某些业务逻辑的一对中的正确一个(详细信息不相关)
我想替换集合中的一个项目及其对,用上述方法的结果 - 这样每个集合中一对元素中的 2 个元素被替换为基于这两个计算出的元素。
一些细节:
我们可以假设每个元素只有一对。
每件物品都有配对的 ID,如 属性,如
public class Item {
private String id;
private String pairId;
the equal method is true when the ID of two items are the same.
...getters,setters
}
此外,我要过滤的集合中的引用也存在于全局缓存中,可以从中轻松检索每个项目,例如
globalCache.getItemById(String id)
因此,如果对的 ID 已知,则可以轻松检索到实际的对参考。
什么是优雅的解决方案(也许通过使用 Stream IPA)?最后,唯一的期望是集合包含每对中的一个项目,顺序无关紧要。
对于流,您必须使用索引访问来执行此操作:
List<Item> calculated =
IntStream.range(0, itemList.size() / 2)
.mapToObj(i -> calculateCorrectItem(itemList.get(2*i+0), itemList.get(2*i+1))
.collect(toList());
如果您想根据 ID 合并项目,可以按 ID 对项目进行分组:
itemList.stream()
.collect(groupingBy(Item::getId)) // Yields a Map<IdType, List<Item>>
.values() // Yields a Collection<List<Item>>, where each List<Item> contains items with the same id.
.stream()
.map(is -> /* invoke calculateCorrectItem, handling 1, 2 or more items in the list */)
.collect(...)
我假设无论参数的顺序如何,方法 calculateCorrectItem(Item item1, Item item2)
都会产生相同的结果,并且必须从结果列表中删除重复的结果。
List<Item> items = ... ; // obtain the items
Map<String, Item> itemById = items.stream()
.collect(Collectors.toMap(Item::getId, // relies on uniquness of Id
Function.identity()));
// set is used to alliminate duplicates since their order is not important
Set<Item> itemSet = items.stream()
.map(item-> pairById.containsKey(item.getPairId()) ? item : // if pair isn't present return the same item, othewise merge them
calculateCorrectItem(item, pairById.get(item.getPairId())))
.collect(Collectors.toSet());
List<Item> result = new ArrayList<>(itemSet);
这是使用映射执行可变缩减的另一种方法(如果保留源列表的 ID 对顺序不重要,则可以使用哈希映射):
Collection<Item> correctItems1 = itemList.stream().collect(
LinkedHashMap<String, Item>::new,
(map, item) -> map.merge(item.getPairId(), item, this::calculateCorrectItem),
Map::putAll)
.values();
List<Item> result = new ArrayList<>(correctItems1);
这是另一种使用带有合并功能的 Collectors.toMap
的方法:
- 首先,为演示创建一个记录并用一些数据初始化一个列表
record Item(String getId, int getValue) {
}
Random r = new Random();
List<Item> items = r.ints(10, 1, 5)
.mapToObj(id -> new Item(id+"", r.nextInt(100) + 1))
.toList();
System.out.println("The raw data");
items.forEach(System.out::println);
System.out.println();
- 现在播放列表
- 使用
toMap
的第三个参数“合并”新项目。
Collection<Item> collection = items.stream()
.collect(Collectors.toMap(Item::getId, item->item,
(item1, item2) -> calculateCorrectItem(item1,
item2)))
.values();
System.out.println("The new list of combined items");
collection.forEach(System.out::println);
版画
The raw data
Item[getId=1, getValue=14]
Item[getId=4, getValue=42]
Item[getId=4, getValue=19]
Item[getId=2, getValue=16]
Item[getId=4, getValue=20]
Item[getId=3, getValue=57]
Item[getId=3, getValue=47]
Item[getId=3, getValue=22]
Item[getId=1, getValue=3]
Item[getId=4, getValue=73]
The new list of combined items
Item[getId=1, getValue=17]
Item[getId=2, getValue=16]
Item[getId=3, getValue=126]
Item[getId=4, getValue=154]
上面使用的方法。它只是对值和 returns 一个新的 Item 实例求和。
public static Item calculateCorrectItem(Item one, Item two) {
return new Item(one.getId(), one.getValue() + two.getValue());
}
一个简单的 non-stream 解决方案打印出与以前相同的结果。
Map<String, Item> result = new HashMap<>();
for (Item item : items) {
result.compute(item.getId(),
(k, v) -> v == null ? item : new Item(v.getId(),
v.getValue() + item.getValue()));
}
result.values().forEach(System.out::println);
所以我想知道以下问题的最佳解决方案是什么:
我在 java 集合 ex
中有一个项目列表(自定义 class)List<Item> itemList = ... item1,item2,item3 etc
然而,集合中的每个项目在集合中也有对应的逻辑对(因此这对不一定按集合中的索引彼此跟随)
我有一个像
这样的辅助方法Item calculateCorrectItem(Item item1, Item item2)
哪个可以 return 基于某些业务逻辑的一对中的正确一个(详细信息不相关)
我想替换集合中的一个项目及其对,用上述方法的结果 - 这样每个集合中一对元素中的 2 个元素被替换为基于这两个计算出的元素。
一些细节:
我们可以假设每个元素只有一对。
每件物品都有配对的 ID,如 属性,如
public class Item {
private String id;
private String pairId;
the equal method is true when the ID of two items are the same.
...getters,setters
}
此外,我要过滤的集合中的引用也存在于全局缓存中,可以从中轻松检索每个项目,例如
globalCache.getItemById(String id)
因此,如果对的 ID 已知,则可以轻松检索到实际的对参考。
什么是优雅的解决方案(也许通过使用 Stream IPA)?最后,唯一的期望是集合包含每对中的一个项目,顺序无关紧要。
对于流,您必须使用索引访问来执行此操作:
List<Item> calculated =
IntStream.range(0, itemList.size() / 2)
.mapToObj(i -> calculateCorrectItem(itemList.get(2*i+0), itemList.get(2*i+1))
.collect(toList());
如果您想根据 ID 合并项目,可以按 ID 对项目进行分组:
itemList.stream()
.collect(groupingBy(Item::getId)) // Yields a Map<IdType, List<Item>>
.values() // Yields a Collection<List<Item>>, where each List<Item> contains items with the same id.
.stream()
.map(is -> /* invoke calculateCorrectItem, handling 1, 2 or more items in the list */)
.collect(...)
我假设无论参数的顺序如何,方法 calculateCorrectItem(Item item1, Item item2)
都会产生相同的结果,并且必须从结果列表中删除重复的结果。
List<Item> items = ... ; // obtain the items
Map<String, Item> itemById = items.stream()
.collect(Collectors.toMap(Item::getId, // relies on uniquness of Id
Function.identity()));
// set is used to alliminate duplicates since their order is not important
Set<Item> itemSet = items.stream()
.map(item-> pairById.containsKey(item.getPairId()) ? item : // if pair isn't present return the same item, othewise merge them
calculateCorrectItem(item, pairById.get(item.getPairId())))
.collect(Collectors.toSet());
List<Item> result = new ArrayList<>(itemSet);
这是使用映射执行可变缩减的另一种方法(如果保留源列表的 ID 对顺序不重要,则可以使用哈希映射):
Collection<Item> correctItems1 = itemList.stream().collect(
LinkedHashMap<String, Item>::new,
(map, item) -> map.merge(item.getPairId(), item, this::calculateCorrectItem),
Map::putAll)
.values();
List<Item> result = new ArrayList<>(correctItems1);
这是另一种使用带有合并功能的 Collectors.toMap
的方法:
- 首先,为演示创建一个记录并用一些数据初始化一个列表
record Item(String getId, int getValue) {
}
Random r = new Random();
List<Item> items = r.ints(10, 1, 5)
.mapToObj(id -> new Item(id+"", r.nextInt(100) + 1))
.toList();
System.out.println("The raw data");
items.forEach(System.out::println);
System.out.println();
- 现在播放列表
- 使用
toMap
的第三个参数“合并”新项目。
Collection<Item> collection = items.stream()
.collect(Collectors.toMap(Item::getId, item->item,
(item1, item2) -> calculateCorrectItem(item1,
item2)))
.values();
System.out.println("The new list of combined items");
collection.forEach(System.out::println);
版画
The raw data
Item[getId=1, getValue=14]
Item[getId=4, getValue=42]
Item[getId=4, getValue=19]
Item[getId=2, getValue=16]
Item[getId=4, getValue=20]
Item[getId=3, getValue=57]
Item[getId=3, getValue=47]
Item[getId=3, getValue=22]
Item[getId=1, getValue=3]
Item[getId=4, getValue=73]
The new list of combined items
Item[getId=1, getValue=17]
Item[getId=2, getValue=16]
Item[getId=3, getValue=126]
Item[getId=4, getValue=154]
上面使用的方法。它只是对值和 returns 一个新的 Item 实例求和。
public static Item calculateCorrectItem(Item one, Item two) {
return new Item(one.getId(), one.getValue() + two.getValue());
}
一个简单的 non-stream 解决方案打印出与以前相同的结果。
Map<String, Item> result = new HashMap<>();
for (Item item : items) {
result.compute(item.getId(),
(k, v) -> v == null ? item : new Item(v.getId(),
v.getValue() + item.getValue()));
}
result.values().forEach(System.out::println);