2010-10-19 23 views
28

Me preguntaba cuál es la mejor forma (clojuresque) de comparar un personaje y una cadena en Clojure. Obviamente algo así devuelve false:¿Cuál es la forma más clojuresca de comparar caracteres y cuerdas? (cadena de caracteres única)

(= (first "clojure") "c") 

PORQUE primeros devuelve un java.lang.Character y "C" es una sola cadena de caracteres. ¿Existe una construcción para comparar directamente char y cadena sin invocar un molde? No he encontrado una manera diferente de esto:

(= (str (first "clojure")) "c") 

pero no estoy satisfecho. Alguna idea? Adiós, Alfredo

Respuesta

42

¿Qué tal la interoperación directa de cadenas?

(= (.charAt "clojure" 0) \c)

o

(.startsWith "clojure" "c")

Debe ser tan rápido como se puede conseguir y no asignar un objeto de la SEC (y en su segundo ejemplo una cadena adicional) que se lanza inmediatamente de nuevo sólo para hacer una comparación.

+5

Lo que me gusta de Clojure es que no oculta Java cuando no es necesario, entonces +1. – ponzao

0

Puede simplemente usar str, como lo hizo en su segundo ejemplo. No hay nada realmente malo con eso. Quiero decir, también puedes llamar primero a "c" para convertirlo en personaje, pero realmente no hará la diferencia. ¿Hay alguna razón por la que no haga de esta manera? En realidad, no agrega mucho a su código al llamar a str en el personaje.

+0

No hay una razón en particular, me pregunto cómo puedo administrar la comparación de caracteres y cadenas de una manera que no llena mi código con el molde :) –

22

literales de caracteres se escriben en Clojure \a \b \c ... por lo que simplemente puede escribir

(= (first "clojure") \c) 
+0

Ok, pero esto solo mueve el problema de la cadena para el personaje ... Quiero decir, si necesito ingresar una sola cadena de caracteres, para comparar dicha cadena necesito echar un cuento :) Sin embargo, es un buen consejo, no sabía que podía usar \ c para expresar char Gracias ^^ –

+0

Ver también la [documentación del lector] (http://clojure.org/reader). – kotarak

1

Se puede utilizar la función de toma de clojure.contrib.string. O escriba su propia función que devuelva el primer carácter si es algo que necesita con frecuencia.

6

las cadenas se pueden indexar directamente sin crear una secuencia a partir de entonces y tomando la primera de esa secuencia.

(= (nth "clojure" 0) \c) 
=> true 

llamadas nth a través de este código Java:

static public Object nth(Object coll, int n){ 
    if(coll instanceof Indexed) 
     return ((Indexed) coll).nth(n); <------- 
    return nthFrom(Util.ret1(coll, coll = null), n); 
} 

que se lee de manera eficiente el carácter directamente.

primera llamada a través de este código java:

static public Object first(Object x){ 
    if(x instanceof ISeq) 
     return ((ISeq) x).first(); 
    ISeq seq = seq(x); <----- (1) 
    if(seq == null) 
     return null; 
    return seq.first(); <------ (2) 
} 

que construye una ss para la cadena (1) (construcción de una ss es muy rápido) y luego toma el primer elemento de esa SEC (2). después del regreso, el seq es basura.

Seqs son claramente la forma más idónea de acceder a cualquier cosa secuencial en clojure y no los estoy golpeando en absoluto. Es interesante estar al tanto de lo que estás creando cuando. es probable que todas las llamadas al first con llamadas al nth sean un caso de optimización prematura.si desea que el carbón número 100 en la cadena se recomienda usar una función de acceso indexado como enésimo

en resumen: No se preocupe por las cosas pequeñas :)

2

Fundamentalmente (al menos en el nivel Clojure - aunque vea Kotarak's answer y otros para encontrar alternativas a esto), está comparando dos secuencias: "clojure" y "c". La condición de igualdad es que el primer elemento de cada secuencia es igual. Así que si usted quiere expresar de manera directa que puede hacer

(apply = (map first ["clojure" "c"])) 

o al revés, donde se crea una secuencia perezosa sobre la comparación de igualdad entre cada par de caracteres, y acaba de tomar el primer elemento de la misma:

(first (map = "clojure" "c")) 
+1

Puede usar 'every?' Para extender esto a prefijos arbitrarios (léase: similar a .startsWith): '(every? Identity (map =" clojure "" clo "))'. – kotarak

0
user=> (= (subs "clojure" 0 1) "c") 
true 
user=> (= (str (first "clojure") "c")) 
true 
0

en estos días que no necesariamente tiene que utilizar Java interoperabilidad:

(clojure.string/starts-with? "clojure" "c") 

starts-with? es solo una envoltura delgada (alrededor de .startsWith).

Ahora, si utiliza tanto Clojure como ClojureScript, no tendrá que recordar tanto la interoperabilidad de Java como la de JavaScript.

Cuestiones relacionadas