Reputation: 33
I want to group by two columns using Collectors.groupingBy
.
I wrote the following:
public class TestGroupKey
{
public static void main(String... args) {
List<Item> list = Arrays.asList(
new Item(1, 1, 1),
new Item(1, 1, 2),
new Item(1, 1, 3),
new Item(1, 2, 1),
new Item(1, 2, 2),
new Item(2, 1, 1),
new Item(2, 2, 1),
new Item(2, 3, 1),
new Item(2, 4, 1),
new Item(2, 4, 2),
new Item(2, 4, 3),
new Item(2, 4, 4),
new Item(3, 1, 1),
new Item(3, 1, 2),
new Item(3, 1, 3),
new Item(3, 1, 4),
new Item(3, 2, 1),
new Item(3, 2, 2)
);
Map<CustomKey, List<Item>> tupleGrouping =
list.stream().collect(Collectors.groupingBy(item -> item.customKey));
tupleGrouping.entrySet().stream()
.forEach(entry -> {
System.out.println(entry.getKey());
});
}
public static class Item {
public int topLevelId;
public int secondLevelId;
public int itemId;
public CustomKey customKey;
public Item(int topLevelId, int secondLevelId, int itemId) {
this.topLevelId = topLevelId;
this.secondLevelId = secondLevelId;
this.itemId = itemId;
this.customKey = new CustomKey(topLevelId, secondLevelId);
}
@Override
public String toString() {
return String.format("%d%d%d", this.topLevelId, this.secondLevelId, this.itemId);
}
}
public static class CustomKey {
public int topLevelId;
public int secondLevelId;
public CustomKey(int topLevelId, int secondLevelId) {
this.topLevelId = topLevelId;
this.secondLevelId = secondLevelId;
}
@Override
public String toString() {
return String.format("%d%d", this.topLevelId, this.secondLevelId);
}
}
}
The expected result is
11
12
21
22
23
24
31
32
But actual result is
24
31
23
22
12
21
24
31
31
24
12
32
32
11
11
11
31
I think groupingBy
is not working.
What's the problem with my use of the CustomKey
Class?
Additionally, nested map key is working:
Map<Integer, Map<Integer, List<Item>>> entryGrouping =
list.stream()
.collect(Collectors.groupingBy(atta1 -> atta1.topLevelId,
Collectors.groupingBy(atta2 -> atta2.secondLevelId)));
Upvotes: 3
Views: 1873
Reputation: 393831
Your CustomKey
class doesn't override Object
's equals
method, so groupingBy
considers two CustomKey
s to be equal only if they are the same object (which is never true in your example, since you create a new CustomKey
instance for each Item
).
public static class CustomKey {
...
@Override
public int hashCode ()
{
// if you override equals, you should also override hashCode
}
@Override
public boolean equals (Object other)
{
if (other == this)
return true;
if (!(other instanceof CustomKey))
return false;
CustomKey okey = (CustomKey) other;
return this.topLevelId == okey.topLevelId && this.secondLevelId == okey.secondLevelId;
}
...
}
Upvotes: 5