假设我有以下列表,我想返回一个只有一个人名为"Sam"
- "Fred"
但25
金额
public class Java8Test{
private static class Person {
private String name;
private String lastName;
private int amount;
public Person(String name, String lastName, int amount) {
this.name = name;
this.lastName = lastName;
this.amount = amount;
}
}
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add(new Person("Sam","Fred",10));
people.add(new Person("Sam","Fred",15));
people.add(new Person("Jack","Eddie",10));
// WHAT TO DO HERE ?
}
}
注意:
上面的例子只是为了澄清,我正在寻找的是使用Java 8的一般地图/减少功能。
答案 0 :(得分:5)
您可以迭代people
列表并使用地图合并具有相同name - lastName
对的人:
Map<String, Person> map = new HashMap<>();
people.forEach(p -> map.merge(
p.getName() + " - " + p.getLastName(), // name - lastName
new Person(p.getName(), p.getLastName, p.getAmount()), // copy the person
(o, n) -> o.setAmount(o.getAmount() + n.getAmount()))); // o=old, n=new
根据您的要求,现在map.values()
是缩减 Collection<Person>
。
如果您可以向Person
类添加复制构造函数和几个方法:
public Person(Person another) {
this.name = another.name;
this.lastName = another.lastName;
this.amount = another.amount;
}
public String getFullName() {
return this.name + " - " + this.lastName;
}
public Person merge(Person another) {
this.amount += another.amount;
}
然后,您可以简化代码的第一个版本,如下所示:
Map<String, Person> map = new HashMap<>();
people.forEach(p -> map.merge(p.getFullName(), new Person(p), Person::merge));
这使用了Map.merge
方法,这对这种情况非常有用。
答案 1 :(得分:4)
您可以使用groupingBy
,reducing
和其他内容:
- 使用相同名称和lastName分组Person
- 将其金额的总和相加
- 用这些属性创建一个人
people = people.stream().collect(
Collectors.groupingBy(o -> Arrays.asList(o.name, o.lastName),
Collectors.summingInt(p->p.amount))
.entrySet()
.stream()
.map(Person::apply).collect(Collectors.toList());
people.forEach(System.out::println);
//Prints :
Sam Fred 25
Jack Eddie 10
这两个是相同的(我的IDE建议我,我假设我真的不知道它是如何工作的,如果有人知道的话:在评论中向我们解释)
.map(Person::apply)
.map(e -> new Person(e.getKey().get(0), e.getKey().get(1), e.getValue())
答案 2 :(得分:3)
可能有一种方法可以使用Stream
,Collectors.groupingby
等,但我只是使用旧式循环和一些有用的Java 8函数和lambdas:
Map<List<String>, Person> persons = new LinkedHashMap<>();
for (Person p : people) {
persons.compute(Arrays.asList(p.getName(), p.getLastName()),
(s, p2) -> p2 == null ? p : new Person(p.getName(), p.getLastName(), p.getAmount() + p2.getAmount()));
}
结果是Map
,其值为“聚合”人。
{[Sam, Fred]=Person(name=Sam, lastName=Fred, amount=25),
[Jack, Eddie]=Person(name=Jack, lastName=Eddie, amount=10)}
答案 3 :(得分:3)
我可以想到这种黑客的做法:
TreeSet<Person> res = people.stream()
.collect(Collector.of(
() -> new TreeSet<>(Comparator.comparing(Person::getName)
.thenComparing(Person::getLastName)),
(set, elem) -> {
if (!set.contains(elem)) {
set.add(elem);
} else {
Person p = set.ceiling(elem);
p.setAmount(elem.getAmount() + p.getAmount());
}
},
(left, right) -> {
throw new IllegalArgumentException("not for parallel");
}));
这根本不会改变Person
的定义。这是Set
已归还(根据firstname
和lastname
),但无论如何这就是你想要的。
答案 4 :(得分:3)
您可以使用流Function<Person, List<Object>> key = p -> Arrays.asList(p.name, p.lastName);
final Map<List<Object>, Integer> collect = people.stream()
.collect(Collectors.groupingBy(key, Collectors.summingInt(p -> p.amount)));
System.out.println(collect);
按多列进行分组:
{[Sam, Fred]=25, [Jack, Eddie]=10}
结果
HomeFragmentAdapter adapter = new HomeFragmentAdapter(getChildFragmentManager(), headerLogo);
从那里,您可以从地图值创建新的Person实例。
答案 5 :(得分:0)
您的Person
课程应如下所示:
private static class Person {
private String name;
private String lastName;
private int amount;
public Person(String name, String lastName, int amount) {
this.name = name;
this.lastName = lastName;
this.amount = amount;
}
public String getName() {return name;}
public String getLastName() {return lastName;}
public int getAmount() {return amount;}
public String toString() {
return name + " / " + lastName + " / " + String.valueOf(amount);
}
}
正如您所看到的,我为您的文件添加了公共getter。要实现您的目标,请使用以下代码:
Person person = people.stream()
.filter(p -> p.getName().equals("Sam"))
.filter(p -> p.getLastName().equals("Fred"))
.reduce(new Person("Sam","Fred",0), (p1, p2) -> {
p1.amount += p2.amount;
return new Person("Sam","Fred", p1.amount);
});
people.add(person);
Person p = people.stream()
.reduce((p1, p2) -> p1.amount > p2.amount ? p1 : p2).get();
结果是一个人物对象,数量为25。
答案 6 :(得分:0)
只需使用Collectors.toMap
private static class Person {
String getName() { return name; }
String getLastName() { return lastName;}
int getAmount() { return amount; }
private String name;
private String lastName;
private int amount;
public Person(String name, String lastName, int amount) {
this.name = name;
this.lastName = lastName;
this.amount = amount;
}
}
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add(new Person("Sam", "Fred", 10));
people.add(new Person("Sam", "Fred", 15));
people.add(new Person("Jack", "Eddie", 10));
people.stream()
.collect(Collectors.toMap(
person -> Arrays.asList(person.getName(), person.getLastName()),
Person::getAmount,
Integer::sum)
)
.forEach((key, value) -> System.out.println(key + " " + value));
}