英文:
Java 8: grouping by multiple fields and then sort based on value
问题
我有一个名为 Info 的类
public class Info {
    private String account;
    private String opportunity;
    private Integer value;
    private String desc;
}
我想要根据两个字段(account 和 opportunity)对 Info 列表进行分组,然后根据 value 进行排序。即使如下所示:
在分组和排序之前的 Info 列表:
List<Info> infos = [(account = 1234, opportunity = abs, value = 4, desc= test),
(account = 1234, opportunity = abs, value = 5, desc = testing),
(account = 1234, opportunity = abss, value = 10, desc = vip),
(account = 123, opportunity = abss, value = 8, desc = vip),
(account = 12, opportunity = absddd, value = 4, desc = production),
(account = 12, opportunity = absooo, value = 2, desc = test)]
我期望的分组和排序结果如下,
Map<String, Map<String, List<Info>>> result = {
    1234 = {
        abss = [(account = 1234, opportunity = abss, value = 10, desc = vip)],
        abs = [(account = 1234, opportunity = abs, value = 5, desc = testing),  
               (account = 1234, opportunity = abs, value = 4, desc = test)]
    },
    123 = {
        abss = [(account = 123, opportunity = abss, value = 8, desc = vip)]
    },
    12 = {
        absddd = [(account = 12, opportunity = absddd, value = 4, desc = production)],
        absooo = [(account = 12, opportunity = absooo, value = 2, desc = test)]
    }
}
输出按照 value 排序(10->(5+4)->8->4->2)
我尝试了以下代码 = infos.stream().collect(Collectors.groupingBy(Info::getAccount, Collectors.groupingBy(r -> r.getOpportunity(), Collectors.toList()))) 但是它的排序是随机的。
英文:
I have a class called Info
public class Info {
    private String account;
    private String opportunity;
    private Integer value;
    private String desc;
}
I want to group a list of Info, by two fields(account and then opportunity) and then sort it based on value. i.e.
List of info before grouping and sorting:
List<Info> infos = [(account = 1234, opportunity = abs, value = 4, desc= test),
(account = 1234, opportunity = abs, value = 5, desc = testing),
(account = 1234, opportunity = abss, value = 10, desc = vip),
(account = 123, opportunity = abss, value = 8, desc = vip),
(account = 12, opportunity = absddd, value = 4, desc = production),
(account = 12, opportunity = absooo, value = 2, desc = test)]
The result I expected after grouping and sorting,
Map<String, Map<String, List<Info>>> result = {
	1234 = {
		abss = [(account = 1234, opportunity = abss, value = 10, desc = vip)],
		abs = [(account = 1234, opportunity = abs, value = 5, desc = testing),  
               (account = 1234, opportunity = abs, value = 4, desc = test)]
	},
	123 = {
		abss = [(account = 123, opportunity = abss, value = 8, desc = vip)]
	},
	12 = {
		absddd = [(account = 12, opportunity = absddd, value = 4, desc = production)],
		absooo = [(account = 12, opportunity = absooo, value = 2, desc = test)]
	}
}
o/p is sorted based on value(10->(5+4)->8->4->2)
I have tried so far = infos.stream().collect(Collectors.groupingBy(Info::getAccount, Collectors.groupingBy(r -> r.getOpportunity(), Collectors.toList()))) but its sorting randomly.
答案1
得分: 3
基于 Info 的 value 进行排序,实现以下步骤:
- 通过比较 
value,使流进行 排序,从而分组将按顺序执行。 - 在调用 groupingBy 时,在 
mapFactory中指定 LinkedHashMap,以保留插入顺序。 
以下程序演示了如何实现:
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Info {
	private String account;
	private String opportunity;
	private Integer value;
	private String desc;
	private Info(String account, String opportunity, Integer value, String desc) {
		super();
		this.account = account;
		this.opportunity = opportunity;
		this.value = value;
		this.desc = desc;
	}
	public static void main(String[] args) {
		List<Info> infos = new ArrayList<>();
		infos.add(new Info("12", "absddd", 4, "production"));
		infos.add(new Info("1234", "abss", 10, "vip"));
		infos.add(new Info("1234", "abs", 4, "test"));
		infos.add(new Info("1234", "abs", 5, "testing"));
		infos.add(new Info("123", "abss", 8, "vip"));
		infos.add(new Info("12", "absooo", 2, "test"));
		Map<String, Map<String, List<Info>>> sortedResult = infos.stream().sorted(Info::compareByValueDesc)
				.collect(Collectors.groupingBy(Info::getAccount, LinkedHashMap::new,
						Collectors.groupingBy(r -> r.getOpportunity(), LinkedHashMap::new, Collectors.toList())));
		sortedResult.forEach((key, value) -> System.out.println(key + value.toString()));
	}
	public static int compareByValueDesc(Info other1, Info other2) {
		return -other1.value.compareTo(other2.value);
	}
	public String getAccount() {
		return account;
	}
	public void setAccount(String account) {
		this.account = account;
	}
	public String getOpportunity() {
		return opportunity;
	}
	public void setOpportunity(String opportunity) {
		this.opportunity = opportunity;
	}
	public String toString() {
		return this.value.toString();
	}
}
英文:
To sort base on the value of Info,
- Make the stream sorted, by comparing the 
value, such that grouping will execute in order. - When calling groupingBy, Specify LinkedHashMap in 
mapFactoryto preserve the insertion order . 
Following program demonstrates how to implement.
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Info {
	private String account;
	private String opportunity;
	private Integer value;
	private String desc;
	private Info(String account, String opportunity, Integer value, String desc) {
		super();
		this.account = account;
		this.opportunity = opportunity;
		this.value = value;
		this.desc = desc;
	}
	public static void main(String[] args) {
		List<Info> infos = new ArrayList<>();
		infos.add(new Info("12", "absddd", 4, "production"));
		infos.add(new Info("1234", "abss", 10, "vip"));
		infos.add(new Info("1234", "abs", 4, "test"));
		infos.add(new Info("1234", "abs", 5, "testing"));
		infos.add(new Info("123", "abss", 8, "vip"));
		infos.add(new Info("12", "absooo", 2, "test"));
		Map<String, Map<String, List<Info>>> sortedResult = infos.stream().sorted(Info::compareByValueDesc)
				.collect(Collectors.groupingBy(Info::getAccount, LinkedHashMap::new,
						Collectors.groupingBy(r -> r.getOpportunity(), LinkedHashMap::new, Collectors.toList())));
		sortedResult.forEach((key, value) -> System.out.println(key + value.toString()));
	}
	public static int compareByValueDesc(Info other1, Info other2) {
		return -other1.value.compareTo(other2.value);
	}
	public String getAccount() {
		return account;
	}
	public void setAccount(String account) {
		this.account = account;
	}
	public String getOpportunity() {
		return opportunity;
	}
	public void setOpportunity(String opportunity) {
		this.opportunity = opportunity;
	}
	public String toString() {
		return this.value.toString();
	}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论