Подтвердить что ты не робот

Какой самый clojuresque способ сравнить символы и строку? (одиночная строка char)

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

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

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

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

но я не удовлетворен. Есть идеи? До свидания, Alfredo

4b9b3361

Ответ 1

Как насчет прямого перебора строк?

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

или

(.startsWith "clojure" "c")

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

Ответ 2

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

(= (first "clojure") \c)

Ответ 3

Строки

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

(= (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)
}

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

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

вкратце: не потейте мелкие вещи:)

Ответ 4

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

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

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

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

Ответ 5

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

Ответ 6

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

Ответ 7

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

Ответ 8

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

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

starts-with? - это всего лишь тонкая обертка (около .startsWith).

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