带有多个键的Java 8分组 [英] Java 8 Grouping with Multiple Keys
问题描述
我正在寻求一些帮助,以将具有多个键的列表中的对象列表进行分组.
I am looking for some help in grouping a list of objects from a list with multiple keys.
基本上,我有一个用户列表,其中包含他们的订单列表,我希望能够使用UserName和Address作为键将它们分组在一起.
Basically, I have a list of users which contains a list of their orders and I want to be able to group them together using UserName and Address as the keys.
示例数据:
<UserList>
<User>
<Username>user123</Username>
<Address>London</Address>
<TransactionList>
<TransactionList>
<OrderNumber>1</OrderNumber>
<Cost>3683446.6600</Cost>
</TransactionList>
</TransactionList>
</User>
<User>
<Username>user123</Username>
<Address>London</Address>
<TransactionList>
<TransactionList>
<OrderNumber>3</OrderNumber>
<Cost>500</Cost>
</TransactionList>
</TransactionList>
</User>
<User>
<Username>user12356</Username>
<Address>Manchester</Address>
<TransactionList>
<TransactionList>
<OrderNumber>6</OrderNumber>
<Cost>90000</Cost>
</TransactionList>
</TransactionList>
</User>
<User>
<Username>user12356</Username>
<Address>Manchester</Address>
<TransactionList>
<TransactionList>
<OrderNumber>10</OrderNumber>
<Cost>100</Cost>
</TransactionList>
</TransactionList>
</User>
</UserList>
我要这样订购,以便每个用户只有一个实例,并且其相关交易会根据用户名和地址分组在一个列表中:
I want to order it like this so that each user just has one instance and its related transactions are grouped in a list based off Username and Address:
<UserList>
<User>
<Username>user123</Username>
<Address>London</Address>
<TransactionList>
<TransactionList>
<OrderNumber>1</OrderNumber>
<Cost>3683446.6600</Cost>
</TransactionList>
<TransactionList>
<OrderNumber>3</OrderNumber>
<Cost>500</Cost>
</TransactionList>
</TransactionList>
</User>
<User>
<Username>user12356</Username>
<Address>Manchester</Address>
<TransactionList>
<TransactionList>
<OrderNumber>6</OrderNumber>
<Cost>90000</Cost>
</TransactionList>
<TransactionList>
<OrderNumber>10</OrderNumber>
<Cost>100</Cost>
</TransactionList>
</TransactionList>
</User>
</UserList>
我尝试使用地图来做到这一点:
I have tried to do it using a map:
Map<String, Map<String,List<User>>> map;
map = userLists.getUserList().stream()
.collect(Collectors.groupingBy(User::getUserName, Collectors.groupingBy(User::getAddress)));
这只是我要执行的操作,但我想知道是否有更好的方法使用MultiKey Map或类似的方法,然后迭代并在密钥匹配的情况下列出交易列表.
This is slightly what I am looking to do but I was wondering if there was a better way using MultiKey Map or something like that and then iterate through and put a list of transactions if the key matched.
预先感谢您的帮助.
推荐答案
您的方法没有错,第一步是正确的:先按 userName
然后按 address
.就我个人而言,我将其反转,因为更有可能有更多的用户使用相同的地址,但是顺序对于获得核心结果并不重要.
Your approach is not wrong, the first step is correct: to group the users by the userName
and then address
. Personally, I'd invert it since more likely there are more users with a same address, but the order is not important in terms of achieving a corect result.
我注意到预期的输出看起来像 List< User>
,减少了具有共同特征( userName
和 address
)并连接了 transactionList
列表.尽管带有复合键(例如 $ {userName} _ $ {address}
)的地图似乎有用,但我还是选择 List< User>
顺便说一句,符合预期的输出.
I notice the expected output looks like List<User>
with reduced users with common characteristic (userName
and address
) and concatenated transactionList
lists. Although a map with a composite key (ex. ${userName}_${address}
) might seem helpful, I'd rather choose the List<User>
, which is in comppliant with, by the way, what the expected output is like.
因此,第二步是迭代所有这些条目,并将 Map
中的 List< User>
简化为一个用户.每个 inner 条目都将与一个用户相关联(因为 userName
和 address
都如此).For-each远远胜于此任务.你去了
So, the second step is to iterate all these entries and reduce List<User>
within the Map
into a single user. Each inner entry will be associated with a single user (because of both userName
and address
). For-each is more than suitable for this task. There you go:
Map<String, Map<String,List<User>>> map = userLists.stream()
.collect(Collectors.groupingBy(
User::getUserName,
Collectors.groupingBy(User::getAddress)));
List<User> list = new ArrayList<>(); // stored output
map.forEach((userName, groupedByAddress) -> { // for each 'userName'
groupedByAddress.forEach((address, users) -> { // ... and each 'address'
User userToAdd = new User(); // ...... create an 'User'
userToAdd.setUserName(userName); // ...... with the 'userName'
userToAdd.setAddress(address); // ...... with the 'address'
users.forEach(user -> { // ...... and of each the user's
userToAdd.getTransactionList() // .......... concatenate
.addAll(user.getTransactionList()); // .......... all the transactions
});
});
});
Stream API非常适合分组以获得中间结果,但是,对于这种进一步的缩减,将非常笨拙.
The Stream API is a good for grouping to get an intermediate result, however, for such futher reduction it would be very clumsy.
这篇关于带有多个键的Java 8分组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!