Единственный дубликат в векторе - PullRequest
0 голосов
/ 02 января 2019

Учитывая список целых чисел от 1 до 10 с размером 5, как мне проверить, есть ли в списке только 2 одинаковых целых числа?

Например,

(check '(2 2 4 5 7)) 

выходда, в то время как

(check '(2 1 4 4 4)) 

или

(check '(1 2 3 4 5))

даёт нет

Ответы [ 6 ]

0 голосов
/ 23 января 2019

Аналогично другим, использующим частоты - просто примените дважды

(-> coll
    frequencies
    vals
    frequencies
    (get 2)
    (= 1))

Положительный регистр:

(def coll '(2 2 4 5 7))

frequencies=> {2 2, 4 1, 5 1, 7 1}
vals=> (2 1 1 1)
frequencies=> {2 1, 1 3}
(get (frequencies #) 2)=> 1

Отрицательный регистр:

(def coll '(2 1 4 4 4))

frequencies=> {2 1, 1 1, 4 3}
vals=> (1 1 3)
frequencies=> {1 2, 3 1}
(get (frequencies #) 2)=> nil
0 голосов
/ 13 января 2019

В ответ на просьбу Алана Маллой, вот несколько комбинаторное решение:

(defn check [coll]
  (let [accums (reductions conj #{} coll)]
    (->> (map contains? accums coll)
         (filter identity)
         (= (list true)))))

Это

  • создает ленивую последовательность накапливающего множества;
  • проверяет его на соответствие каждому новому элементу;
  • фильтры для случаев true - тех, где элемент уже присутствует;
  • проверяет, есть ли точно один из них.

Это лениво, но дублирует бизнес сканирования данной коллекции. Я попробовал это на примере Алана Маллоя:

=> (check (list* 1 1 1 (range 1e9)))
false

Это возвращается мгновенно. Расширение диапазона не имеет значения:

=> (check (list* 1 1 1 (range 1e20)))
false

... также возвращается мгновенно.


Отредактировано, чтобы принять предложенное Alan Malloy упрощение, которое мне пришлось изменить, чтобы избежать ошибки в Clojure 1.10.0.

0 голосов
/ 03 января 2019

Ответ Кристиана Гонсалеса элегантен и хорош, если вы уверены, что работаете с небольшим входом.Тем не менее, он стремится: он заставляет весь список ввода, даже когда он в принципе может сказать раньше, что результат будет ложным.Это проблема, если список очень большой или это ленивый список, элементы которого дорого вычислять - попробуйте его на (list* 1 1 1 (range 1e9))!Поэтому я представляю ниже альтернативу, которая замыкает накоротко, как только он обнаруживает второй дубликат:

(defn exactly-one-duplicate? [coll]
  (loop [seen #{}
         xs (seq coll)
         seen-dupe false]
    (if-not xs
      seen-dupe
      (let [x (first xs)]
        (if (contains? seen x)
          (and (not seen-dupe)
               (recur seen (next xs) true))
          (recur (conj seen x) (next xs) seen-dupe))))))

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

0 голосов
/ 03 января 2019
(letfn [(check [xs] (->> xs distinct count (= (dec (count xs)))))]
    (clojure.test/are [input output]
        (= (check input) output)
        [1 2 3 4 5] false
        [1 2 1 4 5] true
        [1 2 1 2 1] false))

но мне нравится короче (но ограничено ровно 5 списками предметов):

(check [xs] (->> xs distinct count (= 4)))
0 голосов
/ 03 января 2019

вы можете сделать что-то вроде этого

(defn check [my-list]
  (not (empty? (filter (fn[[k v]] (= v 2)) (frequencies my-list)))))

(check '(2 4 5 7))
(check '(2 2 4 5 7))
0 голосов
/ 03 января 2019

Вот решение, использующее частоты для подсчета вхождений и фильтра для подсчета количества значений, которые встречаются только дважды:

(defn only-one-pair? [coll]
  (->> coll
       frequencies                ; map with counts of each value in coll
       (filter #(= (second %) 2)) ; Keep values that have 2 occurrences
       count                      ; number of unique values with only 2 occurrences
       (= 1)))                    ; true if only one unique val in coll with 2 occurrences

Что дает:

user=> (only-one-pair? '(2 1 4 4 4))
false
user=> (only-one-pair? '(2 2 4 5 7))
true
user=> (only-one-pair? '(1 2 3 4 5))
false

Промежуточные шаги в функции, чтобы понять, как она работает:

user=> (->> '(2 2 4 5 7) frequencies)
{2 2, 4 1, 5 1, 7 1}
user=> (->> '(2 2 4 5 7) frequencies (filter #(= (second %) 2)))
([2 2])
user=> (->> '(2 2 4 5 7) frequencies (filter #(= (second %) 2)) count)
1

Согласно предложению, функция может использовать более описательное имя, и также рекомендуется использовать предикатные функции a? в конце этого в Clojure. Так может быть что-то вроде только одна пара? лучше, чем просто проверить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...