5


1

文字列内のすべての文字が等しいかどうかを判断する方法

文字列内のすべての文字が等しい(同じ文字で形成されている)かどうかを知る必要があります。 関数は、文字列のすべての要素が特定の文字に等しいかどうかに応じて、trueまたはfalseを返す必要があります。

うまく機能するこの関数を作成しましたが、より最適な(最速の)ソリューションを探しています。文字列には数千の文字を含めることができます。

function AllElementsAreEqual(Element:Char;Str:String):Boolean;
var
  i : Integer;
begin
Result:=True;
 if Str<>'' then
  for i:=1 to Length(Str) do
   if  Str[i]<>Element then
   begin
      Result:= False;
      exit;
   end;
end;
  • UPDATE *最終的にBarry Kelly Suggestionを使用し、 `inline`ディレクティブを追加すると、パフォーマンスが大幅に改善されました。

function AllElementsAreEqual(Const Element:Char;Str:String):Boolean;inline;
type
ArrayInt = Array of Integer;
var
  i    : Integer;
  Delta: Integer;
  List : ArrayInt;
  Test : Integer;
begin
  Result:=True;
  Delta:=(Length(Str) mod  4);
  if Delta<>0 then
  Str:=Str+StringOfChar(Element,4-Delta);
  Test:=Ord(Element) + Ord(Element) shl 8 + Ord(Element) shl 16 + Ord(Element) shl 24;
  List:=ArrayInt(@(Str[1]));

  for i:=0 to ((Length(Str) div 4)-1) do
   if List[i]<>Test  then
    begin
     Result:=False;
     exit;
    end;
end;

*アップデート2 *

申し訳ありませんが、解決策の古い実装(バグあり)を投稿しましたが、現在修正されています。 バリー提案のより良い実装を作成してくれたhttps://stackoverflow.com/users/20786/the-fox[The_Fox]に感謝します。

6 Answer


9


「Ord(Element)+ Ord(Element)shl 8 + Ord(Element)shl 16 + Ord(Element)shl 24`、次に文字列を PIntegerArray(` ^ array [0..MaxInt div 4-1] of Integer`)に型キャストし、それを `Length(Str)div 4`回ループします。文字ではなく整数として比較します。 ただし、最後のいくつかの `Length(str)mod 4`文字を手動で比較する必要があります。


6


バリー・ケリーの提案を間違って実装しました。 Delphi 7でテストすると、最初の実装よりもさらに遅くなり、stringlengthが4で割り切れない場合、間違った結果になります。

次の文字列でテストしました: StringOfChar( 'c'、100000)+ 'x';`そして新しい関数はTrueを返します `AllElementsAreEqual( 'c'、StringOfChar( 'c'、100000)+ 'x') while Falseを返す必要があります。

文字列を4で割り切れるようにしようとしているため失敗しますが、失敗する理由を自分で理解できるため、実装が遅くなり、メモリの割り当てが必要な新しい文字列が作成され、コストがかかります。

別の危険なことは、動的配列(整数の配列)が文字列を指すようにすることです。 両方ともカウントされ、これは奇妙な結果につながる可能性があります。 バリー・ケリーのアドバイスに従って、PIntegerArrayを使用してください!

バリー・ケリーはこれを意味していたと思う:

function AllElementsAreEqual(const aElement: Char; const aStr: string): Boolean;
var
  lIntArray: PIntegerArray;
  i: Integer;
  lTest: Integer;
begin
  Result := True;
  lTest := Ord(aElement) + Ord(aElement) shl 8 + Ord(aElement) shl 16 + Ord(aElement) shl 24;

  lIntArray := @aStr[1];
  for i := 0 to Length(aStr) div 4 - 1 do
    if lIntArray[i] <> lTest then
    begin
      Result := False;
      Exit;
    end;

  for i := Length(aStr) - (Length(aStr) mod 4) + 1 to Length(aStr) do
    if aStr[i] <> aElement then
    begin
      Result := False;
      Exit;
    end;
end;

NB:関数は空の文字列に対してTrueを返しますが、それでいいですか?

NB2:バリー・ケリーの答えをポイントしてください。私のものではありません。これは本当に大きなコメントであり、答えではないからです。


0


StringOfCharを使用して、ターゲットの文字をN回繰り返して文字列を生成し、char-by-charを比較する代わりに文字列比較を実行する場合があります。

(これが実際に高速であるかどうかはわかりません。測定して確認してください)。


0


Select algorithmを実装して、文字を適切な場所からすばやく見つけることができます。これにより、文字列が「True」である場合の速度は向上しませんが、多少速くなります。


0


文字列の長さを取得し、GetMemを使用してメモリに文字列のサイズを割り当てます。 目的の文字でメモリを塗りつぶします。 その後、CompareMemを使用して文字列とメモリを比較します


-3


あなたのコードから理解したことから

Result:= False;

「*:= *」は、変数に値を割り当てるために使用されます。 デルファイの2つの値をどのように比較しますか?