如何在保持顺序的同时将 List<P> 中的元素分组到 Map<K, List<V>> 中?
How do you group elements in a List<P> to a Map<K, List<V>> while retaining order?
我有一个 Google PlaceSummary 对象的列表,这些对象取自 Google 个地点 API。我想按 Google 地点 ID 收集和分组它们,同时保留元素的顺序。我认为可行的是:
Map<String, List<PlaceSummary>> placesGroupedByPlaceId =
places.stream()
.collect(Collectors.groupingBy(
PlaceSummary::getPlaceId,
LinkedHashMap::new,
Collectors.mapping(PlaceSummary::getPlaceId, toList())
));
但它甚至无法编译。看起来应该根据 Java API documentation on Collectors.
之前我有这个代码:
Map<String, List<PlaceSummary>> placesGroupedByPlaceId = places.stream()
.collect(Collectors.groupingBy(PlaceSummary::getPlaceId));
然而,Streams API 上的标准 .collect()
不保留后续 HashMap
中元素的顺序(显然,因为 HashMap
是无序的)。我希望输出是 LinkedHashMap
以便地图按每个桶的插入顺序排序。
但是,我建议的解决方案无法编译。首先,它不识别 PlaceSummary::getPlaceId
因为它说它不是一个函数——尽管我知道它是。其次,它说我不能将LinkedHashMap<Object, Object>
转换成M。M应该是一个泛型集合,所以应该接受。
如何使用 Java 流 API 将列表转换为 LinkedHashMap
?有简洁的方法吗?如果它太难理解,我可能会求助于老派 Java 8 方法。
我注意到有 ,但这没有我想要的解决方案,因为我需要收集 'this' 我专门迭代的对象。
你真的很接近你想要的:
Map<String, List<PlaceSummary>> placesGroupedByPlaceId =
places.stream()
.collect(Collectors.groupingBy(
PlaceSummary::getPlaceId,
LinkedHashMap::new,
Collectors.mapping(Function.identity(), Collectors.toList())
));
在 Collectors.mapping
方法中,您需要提供 PlaceSummary
实例而不是地点 ID。在上面的代码中,我使用了 Function.identity()
:此收集器用于构建值,因此我们需要自己累积位置(而不是它们的 ID)。
注意可以直接写成Collectors.toList()
而不是Collectors.mapping(Function.identity(), Collectors.toList())
。
您目前的代码无法编译,因为它实际上是在创建一个 Map<String, List<String>>
:您正在为每个 ID 累积 ID(这很奇怪)。
您可以将其编写为通用方法:
private static <K, V> Map<K, List<V>> groupByOrdered(List<V> list, Function<V, K> keyFunction) {
return list.stream()
.collect(Collectors.groupingBy(
keyFunction,
LinkedHashMap::new,
Collectors.toList()
));
}
并像这样使用它:
Map<String, List<PlaceSummary>> placesGroupedById = groupByOrdered(places, PlaceSummary::getPlaceId);
我认为您对 final 收集器有点困惑。它仅表示每个地图值中需要包含的内容。不需要辅助 mapping
收集器,因为您只需要原始对象的列表。
Map<String, List<PlaceSummary>> placesGroupedByPlaceId =
places.stream()
.collect(Collectors.groupingBy(PlaceSummary::getPlaceId,
LinkedHashMap::new,
Collectors.toList()));
/**
* I have written this code more generic, if you want then you can group based on any *
* instance variable , id, name etc via passing method reference.
**/
class Student {
private int id;
private String name;
public Student(int id, String name) {this.id = id;this.name = name;}
/**
* @return the id
*/
public int getId() {return id;}
/**
* @param id
* the id to set
*/
public void setId(int id) {this.id = id;}
/**
* @return the name
*/
public String getName() {return name;}
/**
* @param name
* the name to set
*/
public void setName(String name) {this.name = name;}
}
public class StudentMain {
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
list.add(new Student(1, "Amit"));
list.add(new Student(2, "Sumit"));
list.add(new Student(1, "Ram"));
list.add(new Student(2, "Shyam"));
list.add(new Student(3, "Amit"));
list.add(new Student(4, "Pankaj"));
Map<?, List<Student>> studentById = groupByStudentId(list,
Student::getId);
System.out.println(studentById);
Map<?, List<Student>> studentByName = groupByStudentId(list,
Student::getName);
System.out.println(studentByName);
}
private static <K, V> Map<?, List<V>> groupByStudentId(List<V> list,
Function<V, K> keyFunction) {
return list.stream().collect(
Collectors.groupingBy(keyFunction, HashMap::new,
Collectors.toList()));
}
}
如果您需要在保持顺序的同时进行分组并应用函数(减少),也许我会使用类似的方法。
final Map<Integer,Long>map=stream.collect(Collectors.groupingBy(function
,LinkedHashMap::new
,Collectors.collectingAndThen(Collectors.counting(),Function.identity()))
)
我有一个 Google PlaceSummary 对象的列表,这些对象取自 Google 个地点 API。我想按 Google 地点 ID 收集和分组它们,同时保留元素的顺序。我认为可行的是:
Map<String, List<PlaceSummary>> placesGroupedByPlaceId =
places.stream()
.collect(Collectors.groupingBy(
PlaceSummary::getPlaceId,
LinkedHashMap::new,
Collectors.mapping(PlaceSummary::getPlaceId, toList())
));
但它甚至无法编译。看起来应该根据 Java API documentation on Collectors.
之前我有这个代码:
Map<String, List<PlaceSummary>> placesGroupedByPlaceId = places.stream()
.collect(Collectors.groupingBy(PlaceSummary::getPlaceId));
然而,Streams API 上的标准 .collect()
不保留后续 HashMap
中元素的顺序(显然,因为 HashMap
是无序的)。我希望输出是 LinkedHashMap
以便地图按每个桶的插入顺序排序。
但是,我建议的解决方案无法编译。首先,它不识别 PlaceSummary::getPlaceId
因为它说它不是一个函数——尽管我知道它是。其次,它说我不能将LinkedHashMap<Object, Object>
转换成M。M应该是一个泛型集合,所以应该接受。
如何使用 Java 流 API 将列表转换为 LinkedHashMap
?有简洁的方法吗?如果它太难理解,我可能会求助于老派 Java 8 方法。
我注意到有
你真的很接近你想要的:
Map<String, List<PlaceSummary>> placesGroupedByPlaceId =
places.stream()
.collect(Collectors.groupingBy(
PlaceSummary::getPlaceId,
LinkedHashMap::new,
Collectors.mapping(Function.identity(), Collectors.toList())
));
在 Collectors.mapping
方法中,您需要提供 PlaceSummary
实例而不是地点 ID。在上面的代码中,我使用了 Function.identity()
:此收集器用于构建值,因此我们需要自己累积位置(而不是它们的 ID)。
注意可以直接写成Collectors.toList()
而不是Collectors.mapping(Function.identity(), Collectors.toList())
。
您目前的代码无法编译,因为它实际上是在创建一个 Map<String, List<String>>
:您正在为每个 ID 累积 ID(这很奇怪)。
您可以将其编写为通用方法:
private static <K, V> Map<K, List<V>> groupByOrdered(List<V> list, Function<V, K> keyFunction) {
return list.stream()
.collect(Collectors.groupingBy(
keyFunction,
LinkedHashMap::new,
Collectors.toList()
));
}
并像这样使用它:
Map<String, List<PlaceSummary>> placesGroupedById = groupByOrdered(places, PlaceSummary::getPlaceId);
我认为您对 final 收集器有点困惑。它仅表示每个地图值中需要包含的内容。不需要辅助 mapping
收集器,因为您只需要原始对象的列表。
Map<String, List<PlaceSummary>> placesGroupedByPlaceId =
places.stream()
.collect(Collectors.groupingBy(PlaceSummary::getPlaceId,
LinkedHashMap::new,
Collectors.toList()));
/**
* I have written this code more generic, if you want then you can group based on any *
* instance variable , id, name etc via passing method reference.
**/
class Student {
private int id;
private String name;
public Student(int id, String name) {this.id = id;this.name = name;}
/**
* @return the id
*/
public int getId() {return id;}
/**
* @param id
* the id to set
*/
public void setId(int id) {this.id = id;}
/**
* @return the name
*/
public String getName() {return name;}
/**
* @param name
* the name to set
*/
public void setName(String name) {this.name = name;}
}
public class StudentMain {
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
list.add(new Student(1, "Amit"));
list.add(new Student(2, "Sumit"));
list.add(new Student(1, "Ram"));
list.add(new Student(2, "Shyam"));
list.add(new Student(3, "Amit"));
list.add(new Student(4, "Pankaj"));
Map<?, List<Student>> studentById = groupByStudentId(list,
Student::getId);
System.out.println(studentById);
Map<?, List<Student>> studentByName = groupByStudentId(list,
Student::getName);
System.out.println(studentByName);
}
private static <K, V> Map<?, List<V>> groupByStudentId(List<V> list,
Function<V, K> keyFunction) {
return list.stream().collect(
Collectors.groupingBy(keyFunction, HashMap::new,
Collectors.toList()));
}
}
如果您需要在保持顺序的同时进行分组并应用函数(减少),也许我会使用类似的方法。
final Map<Integer,Long>map=stream.collect(Collectors.groupingBy(function
,LinkedHashMap::new
,Collectors.collectingAndThen(Collectors.counting(),Function.identity()))
)