我有一个案例需要汇总Beans/Objects
列表以显示其总特征。让我先解释一下我的要求。我有List
个人详细信息,如下所示:
Person Bank Balance
---------------------
Sam GS 200
Sam JP 200
Sam WF 200
John GS 200
John JP 200
Robin JP 200
Robin JP 200
我想汇总每个人的余额。
Sam 700 <---- Key
------------------
Sam GS 200
Sam JP 300
Sam WF 200
John 500 <---- Key
------------------
John GS 300
John JP 200
Robin 200 <---- Key
------------------
Robin JP 100
Robin JP 100
现在,让我们切换到我的代码 - List
这样的对象,我需要将它们放在Map
中。关键是聚合细节,其值将是详细列表。这是我的尝试,虽然不是那么好:
public Map<Bean, List<Bean>> getAggregation(List<Bean> beans)
{
Map<Bean, ArrayList<Bean>> aggreagtedBeans = new HashMap<Bean, new ArrayList<Bean>>();
for(Bean bean : beans)
{
String name = bean.getName();
boolean presentALready = false;
Bean correspondingKey = null;
for(Bean key :aggreagtedBeans.keySet())
{
if(key.getName().equals(name))
{
presentALready = true;
correspondingKey = key;
}
}
if(presentALready)
{
aggreagtedBeans.put(correspondingKey, aggreagtedBeans.get(correspondingKey).add(bean));
}
else
{
aggreagtedBeans.put(bean, aggreagtedBeans.get(correspondingKey).add(bean));
}
}
return aggreagtedBeans;
}
问题:
即使使用此Map
方法,密钥也会得到修复,因此无法在为特定人员添加每行时更新余额。
限制:
我知道这种用例非常适合数据库order by
子句,但我不能使用它们。这些是Java Objects
。
此外,如果您认为我应该根据我的使用情况使用不同的数据结构,请建议,如果可能请提供代码段。
编辑:
附加Bean
类代码以供参考:
public class Bean
{
String name;
String bank;
int balance;
// constructors and getters
}
答案 0 :(得分:2)
由于Java 8很棒,所以无法帮助自己:
public static void main(String [] args) {
List<Bean> list = new ArrayList<>();
list.add(new Bean("John", 10));
list.add(new Bean("Sam", 666));
list.add(new Bean("Sam", 9));
list.add(new Bean("John", 1));
list.add(new Bean("John", 7));
Map<String, Integer> sum = list.stream().collect(Collectors.groupingBy(Bean::getName, Collectors.summingInt(Bean::getBalance)));
sum.entrySet().forEach(x -> list.add(new Bean(x.getKey(),x.getValue(), true)));
list.sort((x,y) -> {
int nameComp = x.getName().compareTo(y.getName());
if (nameComp == 0)
return x.isSum() ? -1 : 1;
return nameComp;
});
list.forEach(System.out::println);
}
// Bean class with no "bank" variable, but with a new constructor and overloaded .toString()
static class Bean {
private String name;
private int balance;
private final boolean isSum;
Bean(String name, int balance, boolean isSum) {
this.isSum = isSum;
this.name = name;
this.balance = balance;
}
Bean(String name, int balance) {
this.isSum = false;
this.name = name;
this.balance = balance;
}
public String getName() { return name; }
public int getBalance() { return balance; }
public boolean isSum() { return isSum; }
@Override
public String toString() { return name + " | " + balance + (isSum() ? " *Sum*" : ""); }
}
输出:
约翰| 18 Sum
约翰| 10
约翰| 1
约翰| 7
Sam | 675 总和
Sam | 666
Sam | 9
答案 1 :(得分:1)
积累余额需要的是
Map<String, Integer> name2balance = new HashMap<>();
Bean在地图中不是一个非常好的键,你试图为一个人积累数据,因为你在名字和Bean(名称,银行,余额)之间有一个1:n的关系。
特别是对于潜在的易变数据(余额!),这可能会导致麻烦。
答案 2 :(得分:1)
公共类JavTest {
public static void main(String[] args) {
List<Bean> list = new ArrayList<>();
list.add(new Bean("Sam", "GS", 200));
list.add(new Bean("Sam", "JP", 300));
list.add(new Bean("Sam", "WF", 200));
list.add(new Bean("John", "GS", 300));
list.add(new Bean("John", "JP", 200));
list.add(new Bean("Robin", "JP", 100));
list.add(new Bean("Robin", "JP", 100));
HashMap<Bean, ArrayList<Bean> > beans = (HashMap<Bean, ArrayList<Bean>>) getAggregation(list);
Set<Bean> sb = beans.keySet();
for(Bean b : sb){
System.out.println(b.getName() + " " + b.bank + " " + b.balance);
for(Bean bb : beans.get(b)){
System.out.println(bb.getName() + " " + bb.bank + " " + bb.balance);
}
System.out.println("---------------");
}
}
public static Map<Bean, ArrayList<Bean>> getAggregation(List<Bean> beans)
{
//ArrayList<Bean> al = new ArrayList<Bean>();
HashMap<Bean, ArrayList<Bean> > aggreagtedBeans = new HashMap<Bean, ArrayList<Bean>>();
for(Bean bean : beans)
{
String name = bean.getName();
Set<Bean> keys = aggreagtedBeans.keySet();
boolean found = false;
Bean y = null;
for(Bean x : keys){
if(x.name == name){
y = x;
found = true;
break;
}
}
if(found == true){
ArrayList<Bean> al = aggreagtedBeans.get(y);
al.add(bean);
Bean newBean = new Bean(y.name, bean.bank, y.balance + bean.balance);
aggreagtedBeans.remove(y);
aggreagtedBeans.put(newBean, al);
}else{
ArrayList<Bean> tmp = new ArrayList<Bean>();
tmp.add(bean);
aggreagtedBeans.put(bean, tmp);
}
}
return aggreagtedBeans;
}
}
输出:
Sam WF 700 山姆GS 200 Sam JP 300
Robin JP 200 罗宾JP 100
John JP 500 John GS 300
它应该可以工作,但是使用Bean作为密钥效率不高,因为每次要编辑它时都必须将其删除及其数组列表然后重新添加它们!
答案 3 :(得分:1)
尝试这样的事情假设一个人只能在一个银行中拥有一个帐户。
int balOfSam = 0;
int balOfJohn = 0;
int balOfRobin = 0;
for(Bean bean : list){
map.put(bean.getName()+bean.getBank(),bean.getBalance());
}
Set<String> set = map.keySet();
for(String key :set){
if(key.startsWith("Sam"))
balOfSam+=map.get(key);
else if(key.startsWith("John"))
balOfJohn+=map.get(key);
else
balOfRobin+=map.get(key);
}
System.out.println(balOfJohn);
System.out.println(balOfSam);
System.out.println(balOfRobin);
答案 4 :(得分:1)
使用java 8:
List<Bean> allData = Arrays.asList(
new Bean("Sam", "GS", 200),
new Bean("Sam", "JP", 200),
new Bean("Sam", "WF", 200),
new Bean("John", "GS", 200),
new Bean("John", "JP", 200),
new Bean("Robin", "JP", 200),
new Bean("Robin", "JP", 200)
);
allData.stream().collect(
groupingBy(Bean::getName)
).forEach((name, dataForPerson) -> { // dataForPerson is a List<Bean> for the name
int totalForName = dataForPerson.stream()
.mapToInt(Bean::getBalance)
.sum();
System.out.printf( /* print header for each person */
"%n%-14s%d%n-----------------%n",
name,
totalForName);
dataForPerson.forEach( /* print each entry for the person *//
b->System.out.printf(
"%7s%5s%5s%n",
b.getName(),
b.getBank(),
b.getBalance()
)
);
});
输出:
John 400
-----------------
John GS 200
John JP 200
Robin 400
-----------------
Robin JP 200
Robin JP 200
Sam 600
-----------------
Sam GS 200
Sam JP 200
Sam WF 200