问题描述
我正在处理一个项目,该项目提示用户创建并用整数填充数组,然后显示该数组的均值、众数、中位数和标准差。它首先询问用户数组的大小,输入的数字将声明和初始化数组。然后程序会迭代几次,要求用户声明一个整数值,每个值都会存储到数组中,直到数组被填满。然后程序将打印数组的内容,以及均值、众数、中位数和标准差。
我的代码似乎满足所有这些要求。但是,我正在努力的一件事是模式。虽然它确实打印出数组中重复次数最多的数字,但它没有考虑具有相同重复次数的多个模式,也没有考虑如果没有模式会发生什么。
现在,如果两个数字各输入两次,则显示的模式是第一个重复多次的数字。例如,如果我有一个大小为 10 个整数的数组,并且我输入的整数为 1、2、2、3、3、4、5、6、7、8,它将打印出“2.0”作为模式打印“2.0”和“3.0”。如果没有模式,它只是输入最初输入的数字,而不是说“无”。
实现这一目标的最佳行动方案是什么?
这是我的代码:
.fullScreenCover(isPresented: $ShowSecondView,content: SecondView(ShowSecondView: $ShowSecondView))
解决方法
首先是代码,然后是解释。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.stream.Collectors;
public class ArrayStatistics {
public static void main(String[] args) {
int total = 0;
Scanner input = new Scanner(System.in);
System.out.print("Enter the size of your array >> ");
int size = input.nextInt();
int[] myArray = new int[size];
Map<Integer,Integer> frequencies = new HashMap<>();
System.out.print("Enter the integer values >> ");
for (int i = 0; i < size; i++) {
myArray[i] = input.nextInt();
if (frequencies.containsKey(myArray[i])) {
int frequency = frequencies.get(myArray[i]);
frequencies.put(myArray[i],frequency + 1);
}
else {
frequencies.put(myArray[i],1);
}
total += myArray[i];
}
System.out.println("\nIntegers:");
for (int i = 0; i < size; i++) {
System.out.println(myArray[i]);
}
double mean = calculateMean(size,total);
System.out.println("\nMean: " + mean);
List<Integer> mode = calculateMode(frequencies);
System.out.println("Mode: " + mode);
double median = calculateMedian(myArray);
System.out.println("Median: " + median);
double stdDev = calculateSD(mean,total,size,myArray);
System.out.format("Standard Deviation: %.6f",stdDev);
}
public static double calculateMean(int count,int total) {
double mean = ((double) total) / count;
return mean;
}
public static List<Integer> calculateMode(Map<Integer,Integer> frequencies) {
Map<Integer,Integer> sorted = frequencies.entrySet()
.stream()
.sorted((e1,e2) -> e2.getValue() - e1.getValue())
.collect(Collectors.toMap(e -> e.getKey(),e -> e.getValue(),(i1,i2) -> i1,LinkedHashMap::new));
Iterator<Integer> iterator = sorted.keySet().iterator();
Integer first = iterator.next();
Integer val = sorted.get(first);
List<Integer> modes = new ArrayList<>();
if (val > 1) {
modes.add(first);
while (iterator.hasNext()) {
Integer next = iterator.next();
Integer nextVal = sorted.get(next);
if (nextVal.equals(val)) {
modes.add(next);
}
else {
break;
}
}
}
return modes;
}
public static double calculateMedian(int myArray[]) {
Arrays.sort(myArray);
int val = myArray.length / 2;
double median = ((myArray[val] + myArray[val - 1]) / 2.0);
return median;
}
public static double calculateSD(double mean,int sum,int length,int[] myArray) {
double standardDeviation = 0.0;
for (double num : myArray) {
standardDeviation += Math.pow(num - mean,2);
}
return Math.sqrt(standardDeviation / length);
}
}
为了确定模式,您需要跟踪输入到数组中的整数的出现次数。我使用 Map
来做到这一点。我还在输入整数时计算总数。我在需要它的方法中使用这个总数,例如 calculateMean
。每次需要时重新计算总数似乎是额外的工作。
您正在处理整数,那么为什么将 myArray
声明为 double
的数组?因此我将其更改为 int
数组。
您的问题是如何确定模式。因此我重构了方法 calculatMode
。为了确定模式,您需要询问频率,因此是方法参数。由于您声称可以有零种、一种或多种模式,因此该方法返回 List
。首先,我根据值对 Map
条目进行排序,即特定整数在 myArray
中的出现次数。我按降序对条目进行排序。然后我将所有已排序的条目收集到 LinkedHashMap
中,因为这是一个按照添加顺序存储其条目的映射。因此,LinkedHashMap
中的第一个条目将是出现次数最多的整数。如果第一个映射条目的出现次数为 1(一),则表示没有模式(根据我发现的此 definition):
如果列表中没有重复的数字,则列表没有模式。
在没有模式的情况下,方法 calculateMode
返回一个空的 List
。
如果第一个条目出现的次数超过一次,我会将整数添加到 List
。然后我遍历剩余的地图条目并将整数添加到 List
,如果它的出现次数等于第一个地图条目的出现次数。只要条目中出现的次数不等于第一个条目的次数,我就会退出 while
循环。现在 List
包含 myArray
中出现次数最多的所有整数。
这是一个示例运行(使用您问题中的示例数据):
Enter the size of your array >> 10
Enter the integer values >> 1 2 2 3 3 4 5 6 7 8
Integers:
1
2
2
3
3
4
5
6
7
8
Mean: 4.1
Mode: [2,3]
Median: 3.5
Standard Deviation: 2.211334