代码之家  ›  专栏  ›  技术社区  ›  Ralph java.is.for.desktop

Clojure压缩向量

  •  4
  • Ralph java.is.for.desktop  · 技术社区  · 14 年前

    我试图找到一种习惯用法来“压缩”向量:

    (shift-nils-left [:a :b :c :a nil :d nil])
    ;=> (true [nil nil :a :b :c :a :d])
    (shift-nils-left [nil :a])
    ;=> (false [nil :a])
    (shift-nils-left [:a nil])
    ;=> (true [nil :a])
    (shift-nils-left [:a :b])
    ;=> (false [:a :b])
    

    换句话说,我想把所有 nil 值到向量的左端,而不更改长度。布尔值指示是否发生任何移位。“外部”结构可以是任何 seq ,但内部结果应该是向量。

    我怀疑这项职能将涉及 filter (关于零值)和 into 添加到向量 与原始长度相同,但我不确定如何将结果还原为原始长度。我知道如何做到这一点,但我怀疑Clojure将能够在一行中做到这一点。

    我正在考虑写一个宝石球员作为练习学习Clojure。

    谢谢。

    4 回复  |  直到 14 年前
        1
  •  2
  •   dreish    14 年前

    我会这样写:

    (ns ...
      (:require [clojure.contrib.seq-utils :as seq-utils]))
    
    (defn compress-vec
      "Returns a list containing a boolean value indicating whether the
      vector was changed, and a vector with all the nils in the given
      vector shifted to the beginning."
      ([v]
         (let [shifted (vec (apply concat (seq-utils/separate nil? v)))]
           (list (not= v shifted)
                 shifted))))
    

    编辑:所以,和托马斯打我的帖子一样,但我不会使用flatten,以防你最终使用某种seqable对象来表示珠宝。

        2
  •  2
  •   Thomas Wagner    14 年前

    也许这样:

    (defn shift-nils-left
       "separate nil values" 
        [s] 
        (let [s1 (vec (flatten (clojure.contrib.seq/separate nil? s)))] 
            (list (not (= s s1)) s1)))
    
        3
  •  2
  •   kotarak    14 年前

    nil? (complenent nil?) ). 这个 not= 在无移位的最坏情况下第三次遍历输入。

    (defn compress-vec
      [v]
      (let [[shift? nils non-nils]
            (reduce (fn [[shift? nils non-nils] x]
                      (if (nil? x)
                        [(pos? (count non-nils)) (conj nils nil) non-nils]
                        [shift? nils (conj non-nils x)]))
                    [false [] []] v)]
        [shift? (into nils non-nils)]))
    
        4
  •  1
  •   Matt    14 年前
    (def v [1 2 nil 4 5 nil 7 8] )
    
    (apply vector (take 8 (concat (filter identity v) (repeat nil))))
    

    这将使用 filter take 8 确保向量大小正确。