[英]How do I find the average of filtered elements from list in Java
I wish to find the average of sales by a particular branch in a given year.我希望找到给定年份特定分支机构的平均销售额。 There is a list which has all the branches and all the years of sale.
有一个列表,其中包含所有分支机构和所有销售年份。 I've tried to use IntStream to filter the elements with the required year and branch but I'm unable to find the average, There is an error showing in indexOfSaleInTheYear.size(), and I am not sure if the average part code is correct.
我尝试使用 IntStream 来过滤具有所需年份和分支的元素,但我无法找到平均值,indexOfSaleInTheYear.size() 中显示错误,我不确定平均值部分代码是否为正确的。 Please help.
请帮忙。 Thank You.
谢谢你。
Scanner avgSale = new Scanner(System.in);
System.out.println("Please enter the year for average sale: \n");
int yearEntered = avgSale.nextInt();
Scanner branchNameForAvg = new Scanner(System.in);
System.out.println("Please enter the branch name whose average sale is to be found, case sensitive: \n");
String branchNameEntered = branchNameForAvg.nextLine();
Stream<Integer> indexOfSalesInTheYear = IntStream.of(0, Sale.allValues.size()).boxed()
.filter(i -> Sale.allYears.get(i).equals(yearEntered))
.filter(i -> Sale.allBranches.get(i).equals(branchNameEntered));
int sum = 0;
for(int j = 0; j < indexOfSalesInTheYear.size(); j++){
sum += j;
}
double avgSaleFinal = sum/indexOfSalesInTheYear.size();
System.out.println("The average sale for the year " + yearEntered + " is " + avgSaleFinal + ".");
}
Here is how I would approach it.这是我将如何处理它。 Instead of separate lists of values, years, and branches, have a list of objects that contain these fields:
有一个包含这些字段的对象列表,而不是单独的值、年份和分支列表:
record Sale(int value, int year, String branch) {
}
Here I am using a record
but if you prefer, need to have mutable Sale
instances, or are using an earlier version of Java, you could adapt this code to use classes with ordinary getters and setters.在这里,我使用的是
record
,但如果您愿意,需要具有可变的Sale
实例,或者正在使用 Java 的早期版本,您可以调整此代码以使用具有普通 getter 和 setter 的类。
List<Sale> sales = List.of(
new Sale(12, 2020, "east"),
new Sale(15, 2020, "west"),
new Sale(13, 2020, "east"),
new Sale(16, 2020, "west"),
new Sale(14, 2020, "east"),
new Sale(17, 2020, "west"),
new Sale(18, 2021, "east"),
new Sale(19, 2021, "west"));
double averageOfSales(int year, String branchName) {
OptionalDouble average = sales.stream()
.filter(sale -> sale.year() == year)
.filter(sale -> sale.branch().equals(branchName))
.mapToInt(sale -> sale.value())
.average();
return average.orElseThrow(() ->
new NoSuchElementException("no matching year and branch"));
}
You may want to simply return the OptionalDouble
or throw a different exception;您可能只想返回
OptionalDouble
或抛出一个不同的异常; it all depends on how you want to handle the case where there are no values for the year and branch name provided.这完全取决于您要如何处理没有提供年份和分支名称的值的情况。 You may even want to just
return 0.0
or NaN or -1.0 or some other sentinel value in that case.在这种情况下,您甚至可能只想
return 0.0
或 NaN 或 -1.0 或其他一些标记值。
There is no need to sum the values yourself or divide by the number of values to find the mean since IntStream
already has methods for finding the sum or average.不需要自己对值求和或除以值的数量来求平均值,因为
IntStream
已经有求和或求平均值的方法。
Keeping the different pieces of data broken out in separate, parallel structures is a common pattern among new Java programmers but it really goes against the concept of object oriented programming or even just abstract data types.保持不同的数据片段分开,并行结构是新的 Java 程序员的常见模式,但它确实违背了面向 object 的编程或什至只是抽象数据类型的概念。 You don't need to keep separate collections of simple values;
您不需要单独保留 collections 的简单值; you can invent your own types that encompass the value, year, branch, month, house number, post code, and whatever else you want to model as part of the domain of the data you're working with.
您可以创建自己的类型,包括值、年份、分支机构、月份、门牌号、邮政编码以及您想要的任何其他类型 model 作为您正在使用的数据域的一部分。
In your existing code, you are never iterating the allValues
list.在您现有的代码中,您永远不会迭代
allValues
列表。 Since you are using streams you can do this.由于您使用的是流,因此您可以这样做。
double average = IntStream.of(0, Sale.allValues.size()-1) // go up to the last index only
.filter(i -> Sale.allYears.get(i).equals(yearEntered))
.filter(i -> Sale.allBranches.get(i).equals(branchNameEntered))
.mapToDouble(i -> Sale.allValues.get(i)) // now you have every sale value for yearEntered and branchNameEntered
.average().orElse(-1); // or if not present, throw error, or get the optional, etc
Really you shouldn't have separate lists, you should have a list of Sale objects.实际上,您不应该有单独的列表,您应该有一个 Sale 对象列表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.