我认为这是一个非常基本的问题,应该有解决方案,但我没有设法找到任何解决方案。我想我需要在术语方面提供更多帮助,关于我应该从哪个方面了解我的问题,但我真的很感激任何帮助。
无论如何,我想实施以下内容:
我有一个对象列表。每个对象的形式如下:
public class ExampleClass {
private String name;
private Double firstDouble;
private Double secondDouble;
+ constructor and a bunch of methods
}
基本上我有一个名称变量和一堆与ExampleClass的每个实例相关联的数字。 name变量不是id,因此列表中可能有几个具有相同名称的ExampleClasses,它们都具有不同的编号。我想做的是创建一个"摘要"从这个清单:
让我们假设我的列表中有以下ExampleClasses:
ExampleClass first = new ExampleClass("apple",1,4);
ExampleClass second = new ExampleClass("pear",6,12);
ExampleClass third = new ExampleClass("apple",5,2);
ExampleClass fourth = new ExampleClass("peach",1,2);
ExampleClass fifth = new ExampleClass("plum",10,25);
在这种情况下,我想从列表中删除第一个或第三个元素,因为它们具有相同的名称,我想用数字进行操作,比如加1和5并乘以4和2。
提前感谢您的帮助!
编辑:我可以通过一堆循环来解决它。但是,我需要我的代码具有可读性和高效性。我不是在寻找带有嵌套循环的强力解决方案,如果有一个好的或更好的解决方案我会感兴趣。答案 0 :(得分:2)
在Java 8中查找按名称分组的所有X值的总和非常简单:
// Find the sum of X and group by name
Map<String, Integer> sumXByName = Stream.of(first, second, third, fourth, fifth)
.collect(groupingBy(ExampleClass::getName,
Collectors.<ExampleClass>summingInt(e -> e.getX())));
// Print the results
sumXByName.entrySet().stream()
.map(e -> e.getKey() + " -> " + e.getValue())
.forEach(System.out::println);
打印:
plum -> 10
apple -> 6
pear -> 6
peach -> 1
但是,找到X和Y的乘积之和需要一个自定义收集器。
static class ExampleStatistics implements Consumer<ExampleClass> {
private Integer sum = 0;
private Integer product = null;
@Override
public void accept(ExampleClass value) {
sum += value.getX();
if (product == null) {
product = value.getY();
} else {
product *= value.getY();
}
}
public ExampleStatistics combine(ExampleStatistics other) {
sum += other.sum;
product *= other.product;
return this;
}
public Integer getSum() {
return sum;
}
public Integer getProduct() {
return product;
}
@Override
public String toString() {
return String.format("Sum X = %d, Product Y = %d", sum, product);
}
}
static class ExampleSummarizer
implements Collector<ExampleClass, ExampleStatistics, ExampleStatistics> {
@Override
public Supplier<ExampleStatistics> supplier() {
return ExampleStatistics::new;
}
@Override
public BiConsumer<ExampleStatistics, ExampleClass> accumulator() {
return (r, t) -> r.accept(t);
}
@Override
public BinaryOperator<ExampleStatistics> combiner() {
return (r, t) -> r.combine(t);
}
@Override
public Function<ExampleStatistics, ExampleStatistics> finisher() {
return i -> i; // identity finish
}
@Override
public Set<Collector.Characteristics> characteristics() {
return Stream.of(Characteristics.IDENTITY_FINISH, Characteristics.UNORDERED)
.collect(toSet());
}
};
现在您可以轻松地总结对象:
// Summarize all examples and group by name
Map<String, ExampleStatistics> statsByName = Stream.of(first, second, third, fourth, fifth)
.collect(groupingBy(ExampleClass::getName, new ExampleSummarizer()));
打印此地图将产生以下结果:
plum -> Sum X = 10, Product Y = 25
apple -> Sum X = 6, Product Y = 8
pear -> Sum X = 6, Product Y = 12
peach -> Sum X = 1, Product Y = 2
编辑:为方便起见,我使用了整数。但是,总结了可用于双打的等价物,例如: summingDouble。
class ExampleClass {
private final String name;
private final Integer x;
private final Integer y;
public ExampleClass(String name, Integer x, Integer y) {
super();
this.name = name;
this.x = x;
this.y = y;
}
public String getName() {
return name;
}
public Integer getX() {
return x;
}
public Integer getY() {
return y;
}
}
答案 1 :(得分:1)
而不是
ExampleClass first = new ExampleClass("apple",1,4);
ExampleClass second = new ExampleClass("pear",6,12);
ExampleClass third = new ExampleClass("apple",5,2);
ExampleClass fourth = new ExampleClass("peach",1,2);
ExampleClass fifth = new ExampleClass("plum",10,25);
使用列表
List<ExampleClass> list = new ArrayList<>(5);
list.add(new ExampleClass("apple",1,4));
...
删除第一个或第三个元素
list.remove(1);
list.remove(3);
我认为,你可以自己做其他事。你应该阅读有关List,Map,Set等的内容。
答案 2 :(得分:1)
使用相同的名称过滤掉ExampleClass的每个实例,因此在我的最终对象列表中,我没有两个具有相同名称变量的对象。
考虑使用您的类实现equals(Object obj)和Comparable接口,或者提供一些创建Comparator对象的方法。
为您的列表实施SortedSet
集合,例如TreeSet
我想用对象的Double变量进行操作 同名。
在将项添加到列表中之前,您可以使用任何Set
继承集合提供的contains(Object obj)方法,这样如果方法返回true
,您就可以对重复项执行某些操作。建议您将equals
实施与Comparable
实施保持一致。