-1

リスト内の値の最小最大値と平均値を計算する単一のアプリケーションを構築しています。

それは実際には温度です。だから私はほぼ正しいと思いますが、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 つのエラーは Error: Incompatible types: got "AnsiString" expected "LongInt" This is for Average := Sum / Count; エラー: 互換性のない型: 取得した "バイトのセット" は "Double" である必要があります。このエラーは Temperatures[K] に関するものです:= lstTemp.Items[K];

これを解決する方法はありますか?

Sum と Count はどちらも整数なので、なぜ機能しないのかわかりません!

ありがとう

4

6 に答える 6

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 := 0Min明らかに、ループを実行する前に非常に大きな値を設定する必要があります。使用できる最適な値は、可能な限り最大の符号付き 32 ビット整数値、つまりMaxInt定数の値である 2^31 - 1 です。

第三に、

Temperatures[K] := lstTemp.Items[K];

はおそらく間違っています。Temperatures整数の配列ですが、lstTemp.Items[K]文字列です(少なくとも によるとStrToInt(lstTemp.Items[i]))。

Temperatures[K] := StrToInt(lstTemp.Items[K]);

第 4Averageに、として宣言しますが、(明らかに)またはintegerのような浮動小数点数である必要があります。realdouble

第五に、

edtAvg.Text:=IntToStr(Average); //Display Average
edtAvg.Text:=IntToStr(Min); //Display Minimum Temp.
edtAvg.Text:=IntToStr(Max); //Display Maximum Temp.

技術的に間違っているわけではありませんが、ほとんどの場合、希望どおりにはなりません。

第 6に、エラーではありませんが、初期化CountAverage0. 最後に、必要なforループは 1 つだけです。

于 2013-09-07T16:17:47.127 に答える
1

これを解決する最も重要なアイデアは、エラー メッセージを正しく読むことです。以前の質問で、「エラーはオーバーロードされた関数か何かであると言っています」とコメントしました。その態度は、問題を理解するのに役立ちません。エラーメッセージを正しく読む必要があります。

この質問では、エラーについて次のように説明します。

したがって、2 つのエラーは Error: Incompatible types: got "AnsiString" expected "LongInt" This is for Average := Sum / Count; エラー: 互換性のない型: 取得した "バイトのセット" は "Double" である必要があります。このエラーは Temperatures[K] に関するものです:= lstTemp.Items[K];

ただし、説明は、提供されたコードに基づいて表示されるはずのエラーに対応していません。

エラーを読んでおらず、誤って正しいことをしてしまうことを期待してやみくもに変更を加え始めたようです。エラーを読まなかったので、エラーが変更されたことに気づきませんでした。そのため、ヘルプを求めて私たちに来たとき、古いエラーに新しいコードを提供したり、その逆を行ったりしました。

エラー メッセージを実際に正しく読んでいれば、問題を自分で解決できたかもしれません。少なくとも、コードと実際に一致する説明を使用して、より適切な質問をすることができたはずです。

平均 := 合計 / カウント;

AverageSumおよびCountすべてとして宣言されていIntegerます。表示されるはずのエラー メッセージは、「互換性のない型: IntegerおよびExtended」です。

エラー メッセージを読めば、とを読む手がかりが得られるはずです。IntegerExtended

ここでの問題は、数学では除算によって有理数が生成されることです。それに対応して、プログラム内の除算演算の結果は整数ではありません。Averageしたがって、またはのいずれかDoubleとして宣言する必要がありますExtended

温度[K] := lstTemp.Items[K];

Temperaturesの配列として宣言されIntegerます。の宣言は示されていませんがlstTemp、他のコードに基づいて、それItemsは として宣言された標準の Delphi コントロールの 1 つですTStrings。したがって、表示されるエラー メッセージ次のとおりです。「互換性のない型:整数文字列」。

エラー メッセージを読めば、5 行前に行ったのと同じことを行う手がかりが得られるはずです。

このエラーの理由は、Delphi が「強く型付けされた」言語であるためです。コンパイラは、特定の種類の間違いを犯さないようにしようとします。lstTempの値の 1 つがである場合に何が起こるか想像してみてください'Hello'。これは整数に変換できません。プログラムで「実行時」エラーが発生します。

この問題を解決するには、コンパイラに次のように伝える必要があります。これを行うには、関数を呼び出しStrToIntます。注: 無効な文字列が関数に渡された場合でも実行時エラーが発生しますが、明示的に変換を行うことを強制することで、入力データの事前検証を行うかどうかを検討できます。


コンパイラによって報告されたエラーについて質問しました。これは、プログラミング中に直面するエラーの 1 種類に過ぎず、通常は最も簡単に解決できます。また、ロジック エラーが発生することもあります。つまり、プログラムは正常にコンパイルされますが、正しく動作しません。Andreas の優れた回答は既にそれらをカバーしているので、繰り返しません。
しかし、私はあなたにいくつかの貴重なアドバイスをします。コンパイラ エラーを解決するというハードルを乗り越え、簡単に解決できるようになったら、できるだけ早く次のことを行う必要があります。

  • コードを徹底的にテストする習慣を身につけてください。
  • 統合デバッガーの使用方法を学習します。
  • その制限について学びます。
  • ロギング、プロファイリング、事前および事後条件チェックなど、その他のデバッグ手法を学びます。

最後に、Min、Max、Sum、または Avg を取得するための単純な関数がないというalcalde の暴言への応答として、別の可能な実装を提供します。

基本的に、暴言は、彼がむしろ次の行に沿って何かを書きたいという事実についてのものでした:

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;

明らかに上記のコードはコンパイルできませんが、少し手を加えるだけで同様のことが実現できます。

彼は次の 2 つの点で完全に正しいです。(1)この実装はよりクリーンで、保守がはるかに簡単で、エラーの可能性が少ないということです。(2) Delphi は、単純にそれを行う方法を提供していません。

実際、トップダウンの設計アプローチに従う場合、これが最初の疑似コードになる可能性があります。返金を要求しないのであれば、トップダウンの設計について教えられるべきです。:)トップダウン設計アプローチの背後にある要点は、理想的な実装
を探しているということです。何があるか、何がないかを気にする必要はありません。現在のライブラリとツールが機能を提供しない場合は、独自の.Min

あなたはプログラマーです。あなたには力があります

私はこれを「希望的観測プログラミング」と呼ぶことがあります。他のものが整っていれば、「これ」のように機能をもっと簡単に実装できるといいのですが。それからあなたはあなたの願いをかなえることに取り掛かります。

これ以上苦労することなく、これが実装です。Math ユニットを使用する必要があります。

type
  { We will call existing functions that take TDoubleArray as input }
  TDoubleArray = array of Double;

  TStringsHelper = class(TStrings)
  { A useful class to help us convert TStrings into TDoubleArray }
  public
    class function Using(AStrings: TStrings): TStringsHelper;
    function AsDoubleArray: TDoubleArray;
  end;

{ TStringsHelper }

function TStringsHelper.AsDoubleArray: TDoubleArray;
var
  LoopI: Integer;
begin
  SetLength(Result, Count);
  for LoopI := 0 to Count - 1 do
  begin
    Result[LoopI] := StrToFloat(Strings[LoopI]);
  end;
end;

class function TStringsHelper.Using(AStrings: TStrings): TStringsHelper;
begin
  Result := TStringsHelper(AStrings);
end;


var
  LTemperatures: TDoubleArray;
begin
  { This code is almost the same as our "ideal" implementation }
  if (lstTemp.Items.Count > 0) then
  begin
    LTemperatures := TStringsHelper.Using(lstTemp.Items).AsDoubleArray;
    edtMin.Text := FloatToStr(MinValue(LTemperatures));
    edtMin.Text := FloatToStr(MaxValue(LTemperatures));
    edtMin.Text := FloatToStr(Mean(LTemperatures));
  end
  else
  begin
    ShowMessage('List is empty');
  end;
end;
于 2013-09-08T17:54:42.933 に答える
1

0909EM の回答は非常によくできていましたが、いくつか意見の相違があります。まず、センチネル値を設定する必要はまったくないと思います。単純に最初の温度値を使用します。第 2 に、If ステートメントの 1 行ごとに Begin と End を配置すると、COBOL のようなレベルの英語の冗長性に近づきます。現状では、この単純な問題が非常に多くのコードを必要とするのは非常に残念です。3 つ目は、StrToIntDef を使用しないことです。Zen Of Python の次の行を思い出してください (Python を知らなくてもかまいません。少なくとも Intersimone の I Ching を取得するまでは、誰もがそれを覚えておく必要があります)。

エラーは黙って通過するべきではありません。

明示的に黙らせない限り。

ユーザーが間違ったデータを温度統計プロシージャに渡すと、StrToIntDef はこれらの値を暗黙のうちにゼロに変換します。これは、予期しない望ましくない動作です。発信者は、(エラーがないため) OK であると想定する回答を返しますが、値は正しくありません (特に平均)。テストで間違った入力が明らかになるように、手順を爆発させる方がはるかに良いことです。

また、For ループを For...in に置き換えます。私はこれを一緒に叩きました:

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.
于 2013-09-07T20:44:26.910 に答える
0

lstTemp.Items[i] にはどのような値がありますか? IntToStr を使用しているため、値は整数 (浮動小数点なし) であると思います。

平均を整数にすることはできません。整数は、浮動小数点を含まない数値 (4 バイト) です。2、3、50、1500、-100 などの単純な数値

Sum = 100、Count = 3 と仮定します。Average はどのようになりますか?

したがって、Double などの float 型の変数を使用する必要があります。

それが役立つことを願っています...

于 2013-09-07T16:19:14.730 に答える