Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure 向量中的单个重复_Clojure - Fatal编程技术网

Clojure 向量中的单个重复

Clojure 向量中的单个重复,clojure,Clojure,给定一个大小为5的从1到10的整数列表,如何检查列表中是否只有2个相同的整数 比如说 (check '(2 2 4 5 7)) 是的,但是 (check '(2 1 4 4 4)) 或 不产生这里有一个解决方案,使用频率来计算出现次数,并使用过滤器来计算只出现两次的值的数量: (defn only-one-pair? [coll] (->> coll frequencies ; map with counts of each v

给定一个大小为5的从1到10的整数列表,如何检查列表中是否只有2个相同的整数

比如说

(check '(2 2 4 5 7)) 
是的,但是

(check '(2 1 4 4 4)) 


不产生

这里有一个解决方案,使用频率来计算出现次数,并使用过滤器来计算只出现两次的值的数量:

(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

根据建议,函数可以使用一个更具描述性的名称,最好的做法是给谓词函数一个?最后在Clojure。也许只有一双?总比检查好。

你可以这样做

(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))
但我喜欢较短但仅限于5项的列表:

(check [xs] (->> xs distinct count (= 4)))
是优雅的,如果你确信你是在一个小的输入上操作的话,那就很棒了。然而,它是急切的:它强制整个输入列表,即使原则上它可以更早地判断结果是错误的。如果列表非常大,或者如果它是一个懒惰的列表,其元素的计算成本很高,那么这就是一个问题-请在列表*1范围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))))))

当然,这比无忧无虑的方法要麻烦得多,但我想不出一种方法来实现这种短路行为,而不需要手工操作。我希望看到通过组合更高级别的功能来实现相同结果的改进。

针对Alan Malloy的请求,这里有一个组合解决方案:

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

创建累加集的惰性序列; 针对每个相应的新元素进行测试; 过滤真实情况——元素已经存在的情况; 测试是否恰好存在其中一个。 它是懒惰的,但确实重复了扫描给定集合的业务。我以艾伦·马洛伊为例进行了尝试:

=> (check (list* 1 1 1 (range 1e9)))
false
这会立即返回。扩大范围没有什么区别:

=> (check (list* 1 1 1 (range 1e20)))
false
。。。也会立即返回


编辑以接受Alan Malloy建议的简化,我必须对其进行修改,以避免Clojure 1.10.0中出现错误

与其他使用频率的方法类似-只需应用两次

(-> 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
否定情况:

(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

你试过什么?您具体需要什么帮助?@Carcigenicate我无法理解这背后的逻辑,我真的无法理解像检查'1 2 3'这样的情况是什么?这也是错误的,只需要一对频率就可以帮助解决这个很好的解决方案,它也适用于其他收集类型。IMHO,最好给函数一个更好的、不太通用的名称,这也反映了它的谓词性质。像这样的东西只包含一对?或者是这样。我同意这一点。如果我没有弄错的话,你的解决方案将复制seen集合中可能巨大的集合,当结果为真时。在这种情况下,你可以用速度换取内存。还是我错了?@StefanKamphausen什么交易?其他解决方案所需的空间至少与此方案相同。如果你不记得到目前为止看到过哪些项目,你将如何找到重复的项目?这一个需要更少的空间,因为一旦它知道它可以停止,它就不会一直积累地图;它也不会为输入中的每个唯一项存储一个无意义的整数。我也忘了复制收藏。我试过了。啊,很好。一个小错误:您应该使用seq和next而不是first和second,否则您可能会在包含boolean或nil的集合上得到错误的答案。编辑:不,我明白了-您正在检查一个已知只包含trues的列表。在这种情况下,您可以将每个pred完全替换为=[true],不是吗?@amalloy try=[true]。它失去了懒惰。那肯定是一只虫子列出真实作品。这是一个非常有趣的结果。我惊讶地发现,=range[]立即返回false,但=[]range无限循环。显然,这种情况一直存在,我只是从来没有注意到。@amalloy如果第一次收集被计算在内,它是否会尝试计算第二次收集,无论是否被计算在内?这是可以避免的。你的票还是我的票?很复杂。问题出在c.l.APersistentVector/doEquiv中,它假设j.u.List的实例有一个快速大小方法,即使每个clojure集合都是一个列表,但并非所有集合都被计算在内。