Java 8:按多个字段分组,然后根据值进行排序

huangapple go评论58阅读模式
英文:

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&lt;Info&gt; 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&lt;String, Map&lt;String, List&lt;Info&gt;&gt;&gt; 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 -&gt; r.getOpportunity(), Collectors.toList()))) but its sorting randomly.

答案1

得分: 3

基于 Infovalue 进行排序,实现以下步骤:

  1. 通过比较 value,使流进行 排序,从而分组将按顺序执行。
  2. 在调用 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,

  1. Make the stream sorted, by comparing the value, such that grouping will execute in order.
  2. When calling groupingBy, Specify LinkedHashMap in mapFactory to 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&lt;Info&gt; infos = new ArrayList&lt;&gt;();
		infos.add(new Info(&quot;12&quot;, &quot;absddd&quot;, 4, &quot;production&quot;));
		infos.add(new Info(&quot;1234&quot;, &quot;abss&quot;, 10, &quot;vip&quot;));
		infos.add(new Info(&quot;1234&quot;, &quot;abs&quot;, 4, &quot;test&quot;));
		infos.add(new Info(&quot;1234&quot;, &quot;abs&quot;, 5, &quot;testing&quot;));
		infos.add(new Info(&quot;123&quot;, &quot;abss&quot;, 8, &quot;vip&quot;));
		infos.add(new Info(&quot;12&quot;, &quot;absooo&quot;, 2, &quot;test&quot;));
		Map&lt;String, Map&lt;String, List&lt;Info&gt;&gt;&gt; sortedResult = infos.stream().sorted(Info::compareByValueDesc)
				.collect(Collectors.groupingBy(Info::getAccount, LinkedHashMap::new,
						Collectors.groupingBy(r -&gt; r.getOpportunity(), LinkedHashMap::new, Collectors.toList())));
		sortedResult.forEach((key, value) -&gt; 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();
	}
}

huangapple
  • 本文由 发表于 2020年9月14日 12:40:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/63878179.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定