【问题标题】:Clojure compress vectorClojure 压缩向量
【发布时间】:2011-04-24 19:26:12
【问题描述】:

我正在尝试找到一种 Clojure 惯用的方法来“压缩”向量:

(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(在 nil 值上)和 into 添加到与原始长度相同的 nils 向量中,但我不确定如何减少结果恢复到原来的长度。我知道如何做到这一点“长手”,但我怀疑 Clojure 将能够在一行中完成。

我正在考虑编写一个 Bejeweled 播放器作为学习 Clojure 的练习。

谢谢。

【问题讨论】:

  • 如果您允许将值向右移动...
  • 我想到的数据结构是一个向量或者8个向量。每个内部向量代表一列珠宝。 apply-move 函数将用nil 值替换消失的珠宝。然后,我将使用“压缩”功能将 nil 值移动到顶部,然后用珠宝重新填充(我已经有了这样做的功能)。

标签: clojure


【解决方案1】:

我会这样写:

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

编辑:所以,就像 Thomas 击败我发布的内容一样,但我不会使用 flatten 以防万一你最终使用某种可排序的对象来表示珠宝。

【讨论】:

  • 我正在考虑为板子使用向量向量。每个内部向量将代表一列(以便珠宝可以掉落)。我将用 nil 替换移除的珠宝,然后使用 shift-nils-left 函数将它们“渗透”到列的顶部。然后我将用一个新的随机宝石替换每个零。珠宝本身可能只是 :red、:white 等关键字。
  • 顺便说一句,我应该知道 Clojure 社区中的某个人会在我之前想到分区问题 :-)
【解决方案2】:

也许这样:

(defn shift-nils-left
   "separate nil values" 
    [s] 
    (let [s1 (vec (flatten (clojure.contrib.seq/separate nil? s)))] 
        (list (not (= s s1)) s1)))

【讨论】:

  • 我应该像 dreish 那样使用 'not='。 ;-)
【解决方案3】:

更底层的方法。它只遍历一次输入 seq 以及一次非 nil 的向量。两个更高级的方法遍历输入序列两次(对于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】:
    (def v [1 2 nil 4 5 nil 7 8] )
    
    (apply vector (take 8 (concat (filter identity v) (repeat nil))))
    

    这会使用filter 在向量中创建一个非 nil 值序列,然后将 nil 附加到序列的末尾。这会将您想要的值作为序列提供,然后将它们转换为向量。 take 8 确保向量大小合适。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-04
      • 2015-04-16
      • 1970-01-01
      • 2019-01-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多