Какой самый удобный способ сравнить символы и строки?(одиночная строка символов) - PullRequest
28 голосов
/ 19 октября 2010

Мне было интересно, какой лучший (clojuresque) способ сравнить символ и строку в Clojure.Очевидно, что-то подобное возвращает false:

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

, потому что first возвращает java.lang.Character , а "c" - строка из одного символаСуществует ли конструкция для непосредственного сравнения char и string без вызова приведения?Я не нашел способа, отличного от этого:

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

, но я не удовлетворен.Есть идеи?Пока, Альфредо

Ответы [ 8 ]

42 голосов
/ 19 октября 2010

Как насчет прямого взаимодействия String?

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

или

(.startsWith "clojure" "c")

Он должен быть настолько быстрым, насколько это возможно, и не выделяет объект seq (и вВаш второй пример - дополнительная строка), которая сразу же выбрасывается снова только для сравнения.

23 голосов
/ 19 октября 2010

Символьные литералы написаны \a \b \c ... в Clojure, поэтому вы можете просто написать

(= (first "clojure") \c)
6 голосов
/ 19 октября 2010

строк можно напрямую индексировать, не создавая последовательность с тех пор и не беря первую из этой последовательности.

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

nth вызывает этот код 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);
}

, который эффективно читает символ непосредственно.

первый вызов этого 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)
}

, который создает последовательность для строки (1) (создание последовательности очень быстро), а затем получает первый элемент из этой последовательности.(2).после возврата seq является мусором.

Очевидно, что Seqs - это самый нелепый способ получить доступ к чему-либо последовательному в clojure, и я их вообще не стучу.Интересно знать, что вы создаете когда.переключение всех ваших вызовов на first с вызовами на nth может быть преждевременной оптимизацией. если вы хотите, чтобы в строке был 100-й символ, я бы предложил использовать индексированную функцию доступа, например, nth

.

2 голосов
/ 20 октября 2010

Принципиально (по крайней мере на уровне Clojure - хотя см. ответ Котарака и другие альтернативы этому), вы сравниваете две последовательности: «clojure» и «c». Условие равенства состоит в том, что первый элемент каждой последовательности равен. Так что если вы хотите выразить это напрямую, вы можете сделать

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

или наоборот, где вы создаете ленивую последовательность по сравнению равенства для каждой пары символов и просто берете ее первый элемент:

(first (map = "clojure" "c"))
1 голос
/ 19 октября 2010

Вы можете использовать функцию take из clojure.contrib.string . Или напишите свою собственную функцию, которая возвращает первый символ, если вам это часто нужно.

0 голосов
/ 05 ноября 2016

В наши дни вам не обязательно использовать взаимодействие Java:

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

starts-with? - это просто тонкая оболочка (около .startsWith).

Так что теперь, еслииспользуйте Clojure и ClojureScript, вам не нужно будет помнить взаимодействие Java и JavaScript.

0 голосов
/ 20 октября 2010
user=> (= (subs "clojure" 0 1) "c")
true
user=> (= (str (first "clojure") "c"))
true
0 голосов
/ 19 октября 2010

Вы можете просто использовать str, как и во втором примере. В этом нет ничего плохого. Я имею в виду, что вы могли бы сначала позвонить на «с», чтобы сделать его персонажем, но это не будет иметь большого значения Есть ли причина, по которой вам не нравится это? Это на самом деле не добавляет ничего к вашему коду, вызывая str для символа.

...