Java 8 分组时不保持顺序
Java 8 is not maintaining the order while grouping
我正在使用 Java 8 按数据分组。但是得到的结果不是按顺序排列的。
Map<GroupingKey, List<Object>> groupedResult = null;
if (!CollectionUtils.isEmpty(groupByColumns)) {
Map<String, Object> mapArr[] = new LinkedHashMap[mapList.size()];
if (!CollectionUtils.isEmpty(mapList)) {
int count = 0;
for (LinkedHashMap<String, Object> map : mapList) {
mapArr[count++] = map;
}
}
Stream<Map<String, Object>> people = Stream.of(mapArr);
groupedResult = people
.collect(Collectors.groupingBy(p -> new GroupingKey(p, groupByColumns), Collectors.mapping((Map<String, Object> p) -> p, toList())));
public static class GroupingKey
public GroupingKey(Map<String, Object> map, List<String> cols) {
keys = new ArrayList<>();
for (String col : cols) {
keys.add(map.get(col));
}
}
// Add appropriate isEqual() ... you IDE should generate this
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final GroupingKey other = (GroupingKey) obj;
if (!Objects.equals(this.keys, other.keys)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 7;
hash = 37 * hash + Objects.hashCode(this.keys);
return hash;
}
@Override
public String toString() {
return keys + "";
}
public ArrayList<Object> getKeys() {
return keys;
}
public void setKeys(ArrayList<Object> keys) {
this.keys = keys;
}
}
我在这里使用我的 class groupingKey,我通过它从 ux 动态传递。如何以排序形式获取此 groupByColumns?
不保持顺序的是存储结果的Map
的属性。如果您需要特定的 Map
行为,则需要 request a particular Map
implementation. E.g. LinkedHashMap
维护插入顺序:
groupedResult = people.collect(Collectors.groupingBy(
p -> new GroupingKey(p, groupByColumns),
LinkedHashMap::new,
Collectors.mapping((Map<String, Object> p) -> p, toList())));
顺便说一句,没有理由在创建Stream
之前将mapList
的内容复制到数组中。您可以简单地调用 mapList.stream()
来获得合适的 Stream
.
此外,Collectors.mapping((Map<String, Object> p) -> p, toList())
已过时。 p->p
是恒等映射,所以根本没有理由请求 mapping
:
groupedResult = mapList.stream().collect(Collectors.groupingBy(
p -> new GroupingKey(p, groupByColumns), LinkedHashMap::new, toList()));
但即使 GroupingKey
也已过时。它基本上包装了一个 List
值,因此您可以首先使用 List
作为键。 List
s 适当地实施 hashCode
和 equals
(但你 不得 修改这些密钥 List
s 之后)。
Map<List<Object>, List<Object>> groupedResult=
mapList.stream().collect(Collectors.groupingBy(
p -> groupByColumns.stream().map(p::get).collect(toList()),
LinkedHashMap::new, toList()));
基于@Holger 的精彩回答。我 post 这是为了帮助那些想要在分组后保持顺序以及更改映射的人。
让我们简化一下,假设我们有一个人员列表(整数年龄、字符串名称、字符串地址...等),我们希望按年龄对姓名进行分组,同时保持年龄顺序:
final LinkedHashMap<Integer, List<String> map = myList
.stream()
.sorted(Comparator.comparing(p -> p.getAge())) //sort list by ages
.collect(Collectors.groupingBy(p -> p.getAge()),
LinkedHashMap::new, //keeps the order
Collectors.mapping(p -> p.getName(), //map name
Collectors.toList())));
我正在使用 Java 8 按数据分组。但是得到的结果不是按顺序排列的。
Map<GroupingKey, List<Object>> groupedResult = null;
if (!CollectionUtils.isEmpty(groupByColumns)) {
Map<String, Object> mapArr[] = new LinkedHashMap[mapList.size()];
if (!CollectionUtils.isEmpty(mapList)) {
int count = 0;
for (LinkedHashMap<String, Object> map : mapList) {
mapArr[count++] = map;
}
}
Stream<Map<String, Object>> people = Stream.of(mapArr);
groupedResult = people
.collect(Collectors.groupingBy(p -> new GroupingKey(p, groupByColumns), Collectors.mapping((Map<String, Object> p) -> p, toList())));
public static class GroupingKey
public GroupingKey(Map<String, Object> map, List<String> cols) {
keys = new ArrayList<>();
for (String col : cols) {
keys.add(map.get(col));
}
}
// Add appropriate isEqual() ... you IDE should generate this
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final GroupingKey other = (GroupingKey) obj;
if (!Objects.equals(this.keys, other.keys)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 7;
hash = 37 * hash + Objects.hashCode(this.keys);
return hash;
}
@Override
public String toString() {
return keys + "";
}
public ArrayList<Object> getKeys() {
return keys;
}
public void setKeys(ArrayList<Object> keys) {
this.keys = keys;
}
}
我在这里使用我的 class groupingKey,我通过它从 ux 动态传递。如何以排序形式获取此 groupByColumns?
不保持顺序的是存储结果的Map
的属性。如果您需要特定的 Map
行为,则需要 request a particular Map
implementation. E.g. LinkedHashMap
维护插入顺序:
groupedResult = people.collect(Collectors.groupingBy(
p -> new GroupingKey(p, groupByColumns),
LinkedHashMap::new,
Collectors.mapping((Map<String, Object> p) -> p, toList())));
顺便说一句,没有理由在创建Stream
之前将mapList
的内容复制到数组中。您可以简单地调用 mapList.stream()
来获得合适的 Stream
.
此外,Collectors.mapping((Map<String, Object> p) -> p, toList())
已过时。 p->p
是恒等映射,所以根本没有理由请求 mapping
:
groupedResult = mapList.stream().collect(Collectors.groupingBy(
p -> new GroupingKey(p, groupByColumns), LinkedHashMap::new, toList()));
但即使 GroupingKey
也已过时。它基本上包装了一个 List
值,因此您可以首先使用 List
作为键。 List
s 适当地实施 hashCode
和 equals
(但你 不得 修改这些密钥 List
s 之后)。
Map<List<Object>, List<Object>> groupedResult=
mapList.stream().collect(Collectors.groupingBy(
p -> groupByColumns.stream().map(p::get).collect(toList()),
LinkedHashMap::new, toList()));
基于@Holger 的精彩回答。我 post 这是为了帮助那些想要在分组后保持顺序以及更改映射的人。
让我们简化一下,假设我们有一个人员列表(整数年龄、字符串名称、字符串地址...等),我们希望按年龄对姓名进行分组,同时保持年龄顺序:
final LinkedHashMap<Integer, List<String> map = myList
.stream()
.sorted(Comparator.comparing(p -> p.getAge())) //sort list by ages
.collect(Collectors.groupingBy(p -> p.getAge()),
LinkedHashMap::new, //keeps the order
Collectors.mapping(p -> p.getName(), //map name
Collectors.toList())));