【问题标题】:Functional/idiomatic way to express this Python in Clojure在 Clojure 中表达此 Python 的功能/惯用方式
【发布时间】:2016-05-31 07:23:10
【问题描述】:

我有一个数据转换让我有点受阻。我无法在 Clojure 中表达自己,甚至我精通的 Python 仍然感觉很恶心。

我需要一个像这样的数据结构:

[1, 2, [3, 4], 5, 6]

生成这样的结构:

[[1, 2, 3, 5, 6]
 [1, 2, 4, 5, 6]]

每个子集合创建一个新集合,其中包含迄今为止累积的项目。我只期望单层嵌套。

我的 python 尝试如下所示:

def foo(path, acc_list=[[]]):
    for val in path:
        if not isinstance(val, list):
            for acc in acc_list:
                acc.append(val)
        else:
            for subval in val:
                new = acc_list[0][:]
                new.append(subval)
                acc_list.append(new)
            del acc_list[0]
    return acc_list

foo([1, 2, [3, 4], 5, 6])
# => [[1, 2, 3, 5, 6], [1, 2, 4, 5, 6]]

我想知道 Clojure 解决方案是什么,以及(更重要的是)导致该解决方案的想法。

更新

  • 整数只是举例,它们也可以是关键字或字符串,不一定要排序,但显然必须保留顺序。

  • 通过嵌套,我的意思是它不会像 [1 [2 [3 [4 5] 6] 7] 8] 而是更像 [1 [2 3] 4 [5] 6 [7 8 9]] - 浅。

【问题讨论】:

  • 为什么结果包含 2 个列表?

标签: python clojure transformation


【解决方案1】:

许多 Clo​​jure 核心库函数的一个重要特性是能够处理惰性(可能是无限)序列;因此,我认为一个好的(惯用的)Clojure 解决方案将能够正确扩展包含无限惰性序列的子序列的输入。例如:

[:a :b (range) :c]

应该扩展到

((:a :b 0 :c) (:a :b 1 :c) (:a :b 2 :c) (:a :b 3 :c) ...)

如果顶级序列也可以是无限的并且可以延迟处理,那就太好了,但是,我认为这个问题不可能。 (但如果其他人能想出一种方法来实际处理这个问题,我会感到非常惊讶!)

这是我的解决方案:

(defn expand-subseqs [[x & xs]]
  (when-not (nil? x)
    (let [heads (if (sequential? x) x [x])
          tails (expand-subseqs xs)]
      (if-not tails (map vector heads)
        (for [z tails, y heads] (cons y z))))))

这里的直觉是您首先递归处理输入序列的尾部,然后将当前头部的每个可能值添加到每个可能的尾部。

一些示例输出:

user=> (expand-subseqs [1, 2, [3, 4], 5, 6])
((1 2 3 5 6) (1 2 4 5 6))
user=> (take 5 (expand-subseqs [:a :b (range) :c [true false]]))
((:a :b 0 :c true) (:a :b 1 :c true) (:a :b 2 :c true) (:a :b 3 :c true) (:a :b 4 :c true))

这个解决方案的一个很好的好处是,通过使用cons,我们实际上为每个结果重用了代表尾序列的对象,而不是为每个排列复制整个序列。例如,在上面的最后一个示例中,五个输出中的每一个中的(:c true) 尾序列实际上是同一个对象。

【讨论】:

  • 经过短暂的比赛后,这看起来像门票!谢谢。
【解决方案2】:

我确信还有其他方法可以做到这一点,但这里有一种方法。

user.core=> (def x [1, 2, [3, 4], 5, 6])
#'user.core/x
user.core=> (defn create-vecs [x]
         =>   (let [sub (first (filter vector? x))
         =>         all (remove vector? x)]
         =>   (vec (map #(vec (sort (conj all %))) sub))))
#'user.core/create-vecs
user.core=> (create-vecs x)
[[1 2 3 5 6] [1 2 4 5 6]]

基本上,您获取向量元素和向量的其余部分减去向量元素,然后映射它们以使用conj 创建两个新向量。你需要额外的vec,因为filterremove 返回列表,而不是向量。

【讨论】:

  • 感谢您的回复。 “只需要一层嵌套”我的意思是我不会处理 [1 [2 [3 4] 5] 6] 类型结构,但我 处理 [1 [2 3] 4 [5 6] 7 。 .. ] 类型结构。但这是值得深思的,再次感谢。
  • 哦,整数只是举例,我正在将字符串编译为速记表示,然后将其扩展为路径列表,用于构建与get-inassoc-in 一起使用的路径和update-in。为了清楚起见,我会更新问题。
猜你喜欢
  • 1970-01-01
  • 2014-02-21
  • 1970-01-01
  • 1970-01-01
  • 2013-12-25
  • 2012-06-12
  • 2014-03-12
  • 2023-03-18
  • 1970-01-01
相关资源
最近更新 更多