从列表中获取项目并跟踪修改后的列表

时间:2016-08-25 08:42:35

标签: clojure functional-programming clojurescript

假设有一个名为xs的列表。此列表需要通过谓词进行过滤,并且需要从结果中获取随机元素:

(rand-nth (filter pred? xs))

这将返回列表中的一个项目。如果另外需要保留原始列表(减去提取的项目),该怎么办?

这两个步骤是必要的还是有更快的方法?

(let [item (rand-nth (filter pred? xs))
      new-xs (remove (partial = item) xs)]
   ...)

2 个答案:

答案 0 :(得分:1)

对于输入xs中的重复元素,您的解决方案将失败,因为随机选择所有重复项都会将其删除。

我宁愿自己选择随机索引并直接使用它:

(defn remove-nth [xs n]
  (when (seq xs)
    (if (vector? xs)
      (concat
        (subvec xs 0 n)
        (subvec xs (inc n) (count xs)))
      (concat 
        (take n xs)
        (drop (inc n) xs)))))

(defn remove-random [xs]
  (if (seq xs)
    (let [index (rand-int (count xs))
          item (nth xs index)
          remaining (remove-nth xs index)]
      [item remaining])))

答案 1 :(得分:1)

您也可以在不保留item的绑定的情况下执行此操作:

user> (defn split-rnd [pred coll]
        (let [[l [it & r]] (split-with (complement
                                        #{(rand-nth (filter pred coll))})
                                       coll)]
          [it (concat l r)]))
#'user/split-rnd

user> (split-rnd pos? [-1 2 -3 4 -5 6 -7])
[4 (-1 2 -3 -5 6 -7)]

user> (split-rnd pos? [-1 2 -3 4 -5 6 -7])
[6 (-1 2 -3 4 -5 -7)]

user> (split-rnd pos? [-1 2 -3 4 -5 6 -7])
[2 (-1 -3 4 -5 6 -7)]