【问题标题】:take item from list and keep track of the modified list从列表中获取项目并跟踪修改后的列表
【发布时间】:2016-08-25 08:42:34
【问题描述】:

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

(rand-nth (filter pred? xs))

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

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

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

【问题讨论】:

  • 你真的有性能问题吗?否则你就犯了premature optimization
  • 感谢您的提醒。也许你是对的。如下所述,此方法将删除重复项。但是,我的数据不包含那些(所以它可能是一个集合) - 我会坚持我的路线。
  • 您是否只从每个列表中提取一个元素?您保留剩余部分表明其他情况。

标签: clojure functional-programming clojurescript


【解决方案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])))

【讨论】:

  • 这看起来像是在重新发明轮子。顺便说一句,已经有一个 rand-nth 函数。
  • 是的,我知道,但 OP 还想从随机选择的索引中删除元素,rand-nth 返回一个裸值,没有关于其在原始序列中的位置信息。
  • 好的,我知道了。乍一看,仍然看起来代码太多,OP 解决方案更短,因此更好(从功能性 pov 来看)。
  • 我在回答中也提到了:对于输入集合中的重复项,如果随机选择一个,它们将全部被删除。我的解决方案从所选索引中完全删除一个项目,而不是所有相同的项目。
【解决方案2】:

您也可以这样做,而无需像这样保留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)]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-13
    • 1970-01-01
    • 1970-01-01
    • 2020-07-23
    • 2022-01-22
    • 2011-09-02
    • 1970-01-01
    • 2017-04-04
    相关资源
    最近更新 更多