2010-10-06 30 views
5

Necesito saber si todos los caracteres de una cadena son iguales (formados por el mismo carácter). la función debe devolver verdadero o falso dependiendo de si todos los elementos de la cadena son iguales a un char particular.Cómo determinar si todos los caracteres de una cadena son iguales

Escribí esta función que funciona bien, pero estoy buscando una solución más óptima (más rápida), las cadenas pueden tener miles de caracteres.

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; 

ACTUALIZACIÓN finalmente utilizando la sugerencia Barry Kelly y añadiendo la directiva inline, el rendimiento se ha mejorado significativamente.

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; 

ACTUALIZACIÓN 2

Lo siento, pero he publicado un viejo implementación de la solución (con un error), ahora es fijo. Gracias a The_Fox para crear una mejor implementación de la sugerencia de Barry.

+0

por qué no utilizar el "===" triple igual para lo que se usa. compara si eso es absolutamente = a. Comprueba el tipo de datos y los caracteres – Val

+3

@ Val, ¿desde cuándo Delphi tiene "==="? ¿Estás confundiendo Delphi con JavaScript? –

+0

mi malo Estaba pensando en otra cosa ... – Val

Respuesta

9

Se podría considerar la creación de un valor Integer con el Element repitió 4 veces (ya que es AnsiChar en Delphi 7), desplazada como Ord(Element) + Ord(Element) shl 8 + Ord(Element) shl 16 + Ord(Element) shl 24, entonces Typecast la cadena en un PIntegerArray (^array[0..MaxInt div 4 - 1] of Integer) y el lazo sobre él Length(Str) div 4 veces, comparando como enteros en lugar de caracteres. Sin embargo, necesitará comparar los últimos Length(str) mod 4 caracteres manualmente.

+0

¿Es este el tipo de truco que el compilador Delphi usa para ser tan rápido?;) –

+0

Es uno de los trucos que utiliza para el hash de cadenas y comparaciones, sí. –

0

Quizás use StringOfChar para generar una cadena con el objetivo char repetido N veces, luego haga una comparación de cadenas en lugar de comparar char-by-char.

(No sé si esto es realmente más rápido; medida & ver).

-3

Por lo que entendí de su código

Result:= False; 

": =" se utiliza para asignar un valor a una variable. ¿cómo se comparan 2 valores en Delphi?

+0

Operadores en Delphi: http://library.thinkquest.org/C006657/delphi/operators_in_delphi.htm –

+1

De una manera lógica, con un signo igual, en lugar de igual a igual o === u otra rareza. : = generalmente se lee como "se asigna a" o "se convierte". == viene de "C" (y originalmente "B"). Sin embargo, BCPL utilizó: =, que vino de Algol. Debido a esta extraña decisión (presumiblemente por Thompson y/o Ritchie) miles de errores han sido creados por el mal uso de = en lugar de == –

+0

genio, ¿cómo puedo nunca pensar en eso? Francamente, nunca he visto una respuesta tan brillante, pero te perdiste algo, es decir, la marca ':' se llama * dos puntos * en inglés. Espero que mucha gente aquí continúe votando su respuesta. > - ( – Vantomex

0

Se podría implementar un Select algorithm para encontrar más rápido carbón fuera de lugar, esto no aumentará la velocidad que la cadena es "verdadera", pero debe hacerlo un poco más rápido.

0

Obtenga la longitud de la cadena, use GetMem para asignar memoria del tamaño de la cadena. FillChar la memoria con el char deseado. A continuación, utilice CompareMem para comparar la cadena y la memoria

6

Ha implementado la sugerencia de Barry Kelly equivocada. Cuando la prueba en Delphi 7, es incluso más lento que su primera aplicación y da resultados erróneos si su StringLength no es divisible por 4.

he comprobado con esta cadena: StringOfChar('c', 100000) + 'x'; y su nueva función devuelve True AllElementsAreEqual('c', StringOfChar('c', 100000) + 'x') mientras debería devolver False.

Su implementación es más lenta porque está tratando de dividir su cadena entre cuatro (en la que falla, pero puede averiguar por qué falla) y creando así una nueva cadena que necesita asignaciones de memoria que son costosas.

Otra cosa peligrosa que haces es dejar que una matriz dinámica (matriz de enteros) señale una cadena. Ambos son recontados y esto puede llevar a resultados extraños. ¡Siga los consejos de Barry Kelly y use un PIntegerArray!

creo que Barry Kelly significaba esto:

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: Su función devuelve True para cadenas vacías, es que está bien?

NB2: Por favor, otorgue puntos a la respuesta de Barry Kelly y no la mía, porque este es realmente un comentario de gran tamaño y no una respuesta.

+0

+1 lo siento pero anoche hice muchas pruebas con diferentes implementaciones y publiqué una implementación anterior de la solución propuesta (con un error), ahora está arreglada. Muchas gracias por crear una mejor implementación de la sugerencia de Barry. – Salvador

Cuestiones relacionadas