C# WinsForm,频率分布 Table [更新]
C# WinsForm, Frequency Distribution Table [Updated]
更新01
感谢 Caius,找到了主要问题,“如果”的逻辑是错误的,现在已修复并给出正确的结果。循环仍然在辅助列表上创建比需要更多的位置,主列表上的每个数字都有一个额外的位置。
针对以下问题,我更新了下面的代码以供参考:
-001 我能弄清楚为什么它会创建所需的位置,for 循环应该 运行 只有在 foreach 完成其循环后才正确?
-002 为了解决这个问题,我使用了 List.Remove() 来删除所有的 0,到目前为止没有崩溃,但是,事实上我正在创建额外的索引,而不是删除它们,如果我有大量数字列表,是否意味着性能下降?或者是可接受的解决方案?
描述
它应该读取中央 List1 (numberList) 中的所有数字,并计算特定 (0|-15 / 15|-20) 范围内的数字数量,为此我使用另一个列表,每个range 是 List2 (numberSubList) 上的一个位置,其中 List2 上的每个数字表示该范围内存在多少个数字。
-范围随着数字的增减而变化
代码:
void Frequency()
{
int minNumb = numberList.Min();
int maxNumb = numberList.Max();
int size = numberList.Count();
numberSubList.Clear();
dGrdVFrequency.Rows.Clear();
dGrdVFrequency.Refresh();
double k = (1 + 3.3 * Math.Log10(size));
double h = (maxNumb - minNumb) / k;
lblH.Text = $"H: {Math.Round(h, 2)} / Rounded = {Math.Round(h / 5) * 5}";
lblK.Text = $"K: {Math.Round(k, 4)}";
if (h <= 5) { h = 5; }
else { h = Math.Round(h / 5) * 5; }
int counter = 1;
for (int i = 0; i < size; i++)
{
numberSubList.Add(0); // 001 HERE, creating more positions than needed, each per number.
foreach (int number in numberList)
{
if (number >= (h * i) + minNumb && number < (h * (i + 1)) + minNumb)
{
numberSubList[i] = counter++;
}
}
numberSubList.Remove(0); // 002-This to remove all the extra 0's that are created.
counter = 1;
}
txtBoxSubNum.Clear();
foreach (int number in numberSubList)
{
txtBoxSubNum.AppendText($"{number.ToString()} , ");
}
lblSubTotalIndex.Text = $"Total in List: {numberSubList.Count()}";
lblSubSumIndex.Text = $"Sum of List: {numberSubList.Sum()}";
int inc = 0;
int sum = 0;
foreach (int number in numberSubList)
{
sum = sum + number;
int n = dGrdVFrequency.Rows.Add();
dGrdVFrequency.Rows[n].Cells[0].Value = $"{(h * inc) + minNumb} |- {(h * (1 + inc)) + minNumb}";
dGrdVFrequency.Rows[n].Cells[1].Value = $"{number}";
dGrdVFrequency.Rows[n].Cells[2].Value = $"{sum}";
dGrdVFrequency.Rows[n].Cells[3].Value = $"{(number * 100) / size} %";
dGrdVFrequency.Rows[n].Cells[4].Value = $"{(sum * 100) / size} %";
inc++;
}
}
显示更新版本的屏幕截图。
我认为,如果您的目标是仅将 17 存储在“15 到 25”插槽中,这就很不靠谱了:
if (number <= (h * i) + minNumb) // Check if number is smaller than the range limit
因为它是在一个循环中找到的,该循环将移动到下一个范围,“25 到 35”,它只询问数字 17 是否小于上限(并且 17 小于 35),所以 17 是也符合25-35的范围
FWIW 数字应该在的范围可以从数字中导出,(number - min) / number_of_ranges
- 在您创建例如 10 个范围的那一刻,然后您访问每个数字 10 次以将其放入范围,所以你做的操作比你真正需要的要多 9 倍
更新01 感谢 Caius,找到了主要问题,“如果”的逻辑是错误的,现在已修复并给出正确的结果。循环仍然在辅助列表上创建比需要更多的位置,主列表上的每个数字都有一个额外的位置。
针对以下问题,我更新了下面的代码以供参考:
-001 我能弄清楚为什么它会创建所需的位置,for 循环应该 运行 只有在 foreach 完成其循环后才正确? -002 为了解决这个问题,我使用了 List.Remove() 来删除所有的 0,到目前为止没有崩溃,但是,事实上我正在创建额外的索引,而不是删除它们,如果我有大量数字列表,是否意味着性能下降?或者是可接受的解决方案?
描述
它应该读取中央 List1 (numberList) 中的所有数字,并计算特定 (0|-15 / 15|-20) 范围内的数字数量,为此我使用另一个列表,每个range 是 List2 (numberSubList) 上的一个位置,其中 List2 上的每个数字表示该范围内存在多少个数字。 -范围随着数字的增减而变化
代码:
void Frequency()
{
int minNumb = numberList.Min();
int maxNumb = numberList.Max();
int size = numberList.Count();
numberSubList.Clear();
dGrdVFrequency.Rows.Clear();
dGrdVFrequency.Refresh();
double k = (1 + 3.3 * Math.Log10(size));
double h = (maxNumb - minNumb) / k;
lblH.Text = $"H: {Math.Round(h, 2)} / Rounded = {Math.Round(h / 5) * 5}";
lblK.Text = $"K: {Math.Round(k, 4)}";
if (h <= 5) { h = 5; }
else { h = Math.Round(h / 5) * 5; }
int counter = 1;
for (int i = 0; i < size; i++)
{
numberSubList.Add(0); // 001 HERE, creating more positions than needed, each per number.
foreach (int number in numberList)
{
if (number >= (h * i) + minNumb && number < (h * (i + 1)) + minNumb)
{
numberSubList[i] = counter++;
}
}
numberSubList.Remove(0); // 002-This to remove all the extra 0's that are created.
counter = 1;
}
txtBoxSubNum.Clear();
foreach (int number in numberSubList)
{
txtBoxSubNum.AppendText($"{number.ToString()} , ");
}
lblSubTotalIndex.Text = $"Total in List: {numberSubList.Count()}";
lblSubSumIndex.Text = $"Sum of List: {numberSubList.Sum()}";
int inc = 0;
int sum = 0;
foreach (int number in numberSubList)
{
sum = sum + number;
int n = dGrdVFrequency.Rows.Add();
dGrdVFrequency.Rows[n].Cells[0].Value = $"{(h * inc) + minNumb} |- {(h * (1 + inc)) + minNumb}";
dGrdVFrequency.Rows[n].Cells[1].Value = $"{number}";
dGrdVFrequency.Rows[n].Cells[2].Value = $"{sum}";
dGrdVFrequency.Rows[n].Cells[3].Value = $"{(number * 100) / size} %";
dGrdVFrequency.Rows[n].Cells[4].Value = $"{(sum * 100) / size} %";
inc++;
}
}
显示更新版本的屏幕截图。
我认为,如果您的目标是仅将 17 存储在“15 到 25”插槽中,这就很不靠谱了:
if (number <= (h * i) + minNumb) // Check if number is smaller than the range limit
因为它是在一个循环中找到的,该循环将移动到下一个范围,“25 到 35”,它只询问数字 17 是否小于上限(并且 17 小于 35),所以 17 是也符合25-35的范围
FWIW 数字应该在的范围可以从数字中导出,(number - min) / number_of_ranges
- 在您创建例如 10 个范围的那一刻,然后您访问每个数字 10 次以将其放入范围,所以你做的操作比你真正需要的要多 9 倍