我正在构建一个单独的应用程序来计算列表中的最小值和平均值。
实际上是温度。所以我认为我几乎是正确的,但有2个错误。
var
Count, Average, Sum,i, Max, Min, K : Integer;
Temperatures : Array of Integer;
NoItems : Double;
begin
Count := 0;
Sum := 0;
Max := 0;
Min := 0;
Average := 0;
Count := lstTemp.Items.Count;
{Calculate Sum of Values in the list}
for i := 0 to Count - 1 do
Sum := Sum + StrToInt(lstTemp.Items[i]);
{Calculate Min and Max}
SetLength(Temperatures,Count);
for K:=0 to Count-1 do
Temperatures[K] := lstTemp.Items[K];
if (Temperatures[K] > Max) then
Max := Temperatures[K];
if (Temperatures[K] < Min) then
Min := Temperatures[K];
{Calculate Average}
Average := Sum / Count;
edtAvg.Text:=IntToStr(Average); //Display Average
edtAvg.Text:=IntToStr(Min); //Display Minimum Temp.
edtAvg.Text:=IntToStr(Max); //Display Maximum Temp.
end;
所以2个错误是 错误:不兼容的类型:得到“AnsiString”预期“LongInt” 这是针对平均值:=总和/计数; 错误:不兼容的类型:得到“Set Of Byte”预期“Double” 此错误适用于Temperatures [K]:= lstTemp.Items [K];
任何想法如何解决这个问题?
Sum和Count都是整数,所以我不知道为什么它不起作用!
由于
答案 0 :(得分:7)
存在许多问题。 第一次,当你写
时for K:=0 to Count-1 do
Temperatures[K] := lstTemp.Items[K];
if (Temperatures[K] > Max) then
Max := Temperatures[K];
if (Temperatures[K] < Min) then
Min := Temperatures[K];
你实际上是
for K:=0 to Count-1 do
Temperatures[K] := lstTemp.Items[K];
if (Temperatures[K] > Max) then
Max := Temperatures[K];
if (Temperatures[K] < Min) then
Min := Temperatures[K];
这是胡说八道。您希望所有这些行成为for
循环的一部分:
for K:=0 to Count-1 do
begin
Temperatures[K] := lstTemp.Items[K];
if (Temperatures[K] > Max) then
Max := Temperatures[K];
if (Temperatures[K] < Min) then
Min := Temperatures[K];
end;
第二,为了使此算法有效,Min
(Max
)的初始值需要比列表中的值更大(更小)。这可能适用于Max := 0
,但可能不适用于Min := 0
。显然,在运行循环之前,需要将Min
设置为一个非常大的值。您可以使用的最佳值是最高可能的带符号32位整数值,即2 ^ 31 - 1,这是MaxInt
常量的值。
<强>第三强>,
Temperatures[K] := lstTemp.Items[K];
可能是错的。 Temperatures
是整数的数组,而lstTemp.Items[K]
是字符串(至少根据StrToInt(lstTemp.Items[i])
),所以你需要< / p>
Temperatures[K] := StrToInt(lstTemp.Items[K]);
第四,您将Average
声明为integer
,但它必须是一个浮点数(显然),如real
或{{ 1}}。
<强>第五强>,
double
在技术上不正确,但很可能不会做你想要的。
第六次,虽然不是错误,但您无需初始化edtAvg.Text:=IntToStr(Average); //Display Average
edtAvg.Text:=IntToStr(Min); //Display Minimum Temp.
edtAvg.Text:=IntToStr(Max); //Display Maximum Temp.
和Count
至Average
。最后,您只需要一个0
循环。
答案 1 :(得分:2)
(至少在Delphi 2010中 - 单位数学)有一个函数可以计算一步中的平均值和标准差,以及返回数组中最小值和最大值的函数。 BTW,Mean是所有值的算术平均值,是正确的术语。 (我复制了一个我正在研究并修改为你的例子的例子 - 至少编译它):
type
a = array of double;
var
Temperatures : a;
Average,stddev3, Max, Min : extended;
// Compiler insists on extended for these properties
begin
Max := Math.MaxValue(Temperatures);
Min := Math.MinValue(Temperatures);
Math.MeanAndStdDev(Temperatures ,Average,stddev3);
end;
对于数组使用中的最大值(它采用double数组并返回double):
function MaxValue(const Data: array of Double): Double;
对于最小值,请使用相应的:
function MinValue(const Data: array of Double): Double;
我同意平均值不能是整数,但整数数组有两个相似的函数:
function MinIntValue(const Data: array of Integer): Integer; and
function MaxIntValue(const Data: array of Integer): Integer;
答案 2 :(得分:1)
首先,考虑使用StrToIntDef(String To Integer with Default value)而不是StrToInt(String to Integer),这将产生以下内容......
value := StrToIntDef('Abcdef', 0); // value will be zero
VS
value := StrToInt('Abcdef'); // exception
但问题是你想要温度的整数或浮点值吗? (例如1或1.6?)如果你想要浮点值,可以使用StrToFloatDef ...
其次,我已经看到很多使用Delphi的毕业生犯了这个错误,尝试总是使用开始和结束,它会有所帮助...因为它使得你在if / for /中做的很清楚虽然你打算在外面做什么..
for i := 0 to lstTemp.Items.Count - 1 do
begin
// Sum all the items in the list
Sum := Sum + StrToIntDef(lstTemp.Items[i], 0);
end;
接下来你的数组有点无意义,SetLength和添加项目位是好的,但它不是很实用,当你可以只使用列表中的项目。您需要做的就是挂上最大值和最小值。
然后你的最后一个问题是,平均值不会是一个整数,它会有一个小数部分。例如。 5除以2是2.5,而不是2而不是3.您可以使用trunc返回整数部分,或者更改Average以使其成为浮点数...
for K:=0 to lstTemp.Items.Count-1 do
begin
if (StrToIntDef(lstTemp.Items[K], 0) > Max) then
begin
Max := StrToIntDef(lstTemp.Items[K], 0);
end;
if (StrToIntDef(lstTemp.Items[K], 1000) < Min) then // note, really high number
begin
Min := StrToIntDef(lstTemp.Items[K], 1000);
end;
end;
{Calculate Average}
Average := Trunc(Sum / Count); // do you really want to trunc this? I suspect not.
if Min = 1000 then // just incase
begin
Min := 0;
end;
您将面临的最后一个问题是您始终设置相同文本框的文本...
edtAvg.Text:=IntToStr(Average); //Display Average
edtMin.Text:=IntToStr(Min); //Display Minimum Temp. (I assume this is supposed to be edtMin)
edtMax.Text:=IntToStr(Max); //Display Maximum Temp. (I assume this is supposed to be edtMax)
我想我最后的改进是注意到你只需要一个for循环......
for K:=0 to lstTemp.Items.Count-1 do
begin
// Sum all the items in the list
Sum := Sum + StrToIntDef(lstTemp.Items[K], 0);
if (StrToIntDef(lstTemp.Items[K], Low(Integer)) > Max) then // A really low value
begin
Max := StrToIntDef(lstTemp.Items[K], Low(Integer));
end;
if (StrToIntDef(lstTemp.Items[K], High(Integer)) < Min) then // A really high value
begin
Min := StrToIntDef(lstTemp.Items[K], High(Integer));
end;
end;
答案 3 :(得分:1)
错误绝不应该以无声方式传递。
除非明确沉默。
如果用户将不正确的数据传递到温度统计程序,StrToIntDef将静默地将这些值转换为零,这是一种意外和不希望的行为。调用者将获得他们认为可以接受的答案(因为没有错误),但是会有不正确的值(尤其是平均值)。让程序爆炸是一件好得多的事情,因此测试会显示错误的输入。
我也用For ... in替换For循环。我把它撞在了一起:
program temps;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, System.Classes, Generics.Collections, Math;
Var
someTemps : TStringList;
Procedure TempStats(temperatures : TStringList);
Var
temps : TList<Real>;
minTemp, maxTemp, sumTemps : Real;
numTemps : Integer;
tempStr : String;
temp : Real;
avgTemp : Real;
Begin
numTemps := temperatures.Count;
If numTemps > 0 then
Begin
temps := TList<Real>.Create;
For tempStr in temperatures Do
temps.Add(StrToFloat(tempStr));
minTemp := temps[0];
maxTemp := temps[0];
sumTemps := 0;
For temp in temps Do
Begin
minTemp := Min(minTemp, temp);
maxTemp := Max(maxTemp, temp);
sumTemps := sumTemps + temp;
End;
avgTemp := sumTemps / numTemps;
WriteLn(avgTemp:0:2);
WriteLn(minTemp:0:2);
WriteLn(maxTemp:0:2);
temps.Free;
End
Else
WriteLn('No temperatures passed.');
End;
Begin
someTemps := TStringList.Create;
someTemps.AddStrings(TArray<String>.Create('72', '93', '84', '76', '82'));
TempStats(someTemps);
ReadLn;
someTemps.Clear;
TempStats(someTemps);
someTemps.Free;
ReadLn;
end.
答案 4 :(得分:1)
关于如何解决此问题的最重要的想法是阅读您的错误消息正确。在上一个问题上你评论过:&#34;错误是说它是一个重载函数或某些东西&#34;。这种态度不会帮助你理解这个问题。您需要正确读取错误消息。
在这个问题中,您将对错误进行以下描述:
所以2个错误是错误:不兼容的类型:得到&#34; AnsiString&#34;预期&#34; LongInt&#34;这是针对平均值:=总和/计数;错误:不兼容的类型:得到&#34; Set By Byte&#34;预期&#34; Double&#34;此错误适用于Temperatures [K]:= lstTemp.Items [K];
但是,根据提供的代码,说明与您应该看到的错误不对应。
看起来你没有读你的错误,只是盲目地开始做出改变,希望你不小心做正确的事情。因为您没有读取错误,所以您没有注意到它们发生了变化。因此,当您向我们寻求帮助时,您使用新代码提供了旧错误,反之亦然。
如果您确实正确阅读错误消息,您可能已经能够自己解决问题。至少,您可以使用与代码实际匹配的描述来提出更好的问题。
Average
,Sum
和Count
都声明为Integer
。您应该获取的错误消息是:&#34;不兼容的类型:整数和扩展&#34;。
如果您阅读错误消息,它应该为您提供<{1}}和Integer
上读取的线索。
这里的问题是,在数学中,除法产生一个有理数。并且相应地,程序中的除法运算的结果不是整数。因此,您需要将Extended
声明为Average
或Double
。
Extended
被声明为Temperatures
的数组。您还没有显示Integer
的声明,但根据其他代码,它是lstTemp
声明为Items
的标准Delphi控件之一。因此,您应该获取的错误消息是:&#34;不兼容的类型:整数和字符串&#34;。
如果您阅读错误消息,它应该会为您提供一条线索,让您做出与之前5行相同的事情。
这个错误的原因是Delphi是一个强类型&#34;语言。编译器试图阻止你犯某些错误,因为它更好地抓住它们。想象一下,如果TStrings
中的一个值为lstTemp
,可能会发生什么。那不能转换为整数;并会导致&#34;运行时间&#34;程序错误。
要解决此问题,您需要告诉编译器:&#34;我知道值是一个字符串,可以是任何字符串,但我希望您将其转换为整数&#34;。您可以通过调用'Hello'
函数来完成此操作。注意:如果将无效字符串传递给函数,您仍会遇到运行时错误,但是通过强制显式执行转换,您可以考虑是否要对输入数据进行一些预验证。
您询问了编译器报告的错误。这只是您在编程时遇到的一种错误 - 通常最容易解决。您还会遇到逻辑错误:您的程序成功编译,但行为不正确。 Andreas's excellent answer已经涵盖了那些,所以我不会重复它们 但是,我会给你一些宝贵的建议。一旦你克服了解决编译器错误的障碍,并且能够轻松完成 - 你需要尽快:
最后,作为对alcalde's rant的回应,关于没有任何简单的函数来获得Min,Max,Sum或Avg:我提供了另一种可能的实现。
基本上,咆哮是因为他远远地写了一些东西:
StrToInt
显然上面的代码不会编译,但通过一些工作我们可以实现类似的东西。
他完全正确的两个方面:(1)这个实现更清晰,更容易维护,错误的可能性更小。 (2)德尔福没有提供简单方法。
事实上,如果您遵循自上而下的设计方法,这可能是您的初始伪代码。如果不要求退款,你应该接受自上而下的设计教育。 :)
自上而下设计方法背后的重点是,您正在寻找 理想 实施。你不必担心那里有什么。如果当前的库和工具没有提供begin
if (lstTemp.Count > 0) then
begin
edtMin.Text := lstTemp.Min;
edtMax.Text := lstTemp.Max;
edtAvg.Text := lstTemp.Average;
end
else
begin
ShowMessage('List is empty');
end;
end;
功能,您可以编写自己的。
你是程序员,你有权力 !
我有时喜欢称之为&#34;一厢情愿的编程&#34;。您希望如果有其他的东西到位,我可以更容易地实现这些功能,例如&#34;这个&#34;。然后你就可以实现你的愿望了。
不用多说,这里是实施。您需要使用数学单元。
Min
答案 5 :(得分:0)
lstTemp.Items [i]中有什么值? 我想这些值是整数(没有浮点数),因为你使用的是IntToStr。
平均值不能是整数。整数是一个没有浮点的数字(4个字节)。一个简单的数字,如2,3,50,1500,-100
假设Sum = 100,Count = 3。 平均值是多少?
因此,您必须使用float变量类型,例如Double。
我希望它有所帮助...