Как определить, все ли символы в строке равны - PullRequest
5 голосов
/ 06 октября 2010

Мне нужно знать, все ли символы в строке равны (образованы одним и тем же символом). функция должна возвращать 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 наконец, используя предложение Барри Келли и добавив директиву 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

Прошу прощения, но я разместил старую реализацию решения (с ошибкой), теперь исправлена. Спасибо The_Fox за лучшую реализацию предложения Барри.

Ответы [ 6 ]

9 голосов
/ 06 октября 2010

Можно подумать о создании значения Integer с повторением Element 4 раза (так как в Delphi 7 это AnsiChar), смещенным как 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 голосов
/ 06 октября 2010

Вы ошиблись в предложении Барри Келли.Когда я тестирую его на Delphi 7, он даже медленнее, чем ваша первая реализация, и он дает неверные результаты, если длина вашей строки не делится на 4.

Я проверил это с помощью этой строки: StringOfChar('c', 100000) + 'x'; и вашей новой функциивозвращает True AllElementsAreEqual('c', StringOfChar('c', 100000) + 'x'), в то время как он должен возвращать False.

Ваша реализация медленнее, потому что вы пытаетесь сделать вашу строку делимой на четыре (в которой вы терпите неудачу, но вы сами можете выяснить, почему она терпит неудачу) итаким образом создавая новую строку, которая требует выделения памяти, что является дорогостоящим.

Другая опасная вещь, которую вы делаете, - это позволяет динамическому массиву (массиву целых чисел) указывать на строку.Оба пересчитаны, и это может привести к странным результатам.Пожалуйста, следуйте советам Барри Келли и используйте 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;

Примечание: ваша функция возвращает True для пустых строк, это нормально?

NB2: Пожалуйста, присуждайте баллы за ответ Барри Келли, а не за мой, потому что это действительно слишком большой комментарий, а не ответ.

0 голосов
/ 06 октября 2010

Получите длину строки, используйте GetMem для выделения памяти размера строки. Заполните память нужным символом. Затем используйте CompareMem для сравнения строки и памяти

0 голосов
/ 06 октября 2010

Вы могли бы реализовать алгоритм Select , чтобы быстрее находить символы не на своем месте, это не увеличит скорость, если строка является "True", но должно сделать это несколько быстрее.

0 голосов
/ 06 октября 2010

Из того, что я понял из вашего кода

Result:= False;

": = " используется для присвоения значения переменной. как вы сравниваете 2 значения в Delphi?

0 голосов
/ 06 октября 2010

Возможно, используйте StringOfChar , чтобы сгенерировать строку с целевым символом, повторенным N раз, затем выполнить сравнение строк вместо сравнения char-by-char.

(Не знаю, если это на самом деле быстрее; измерить и посмотреть).

...