我的数据转换让我有点陷入困境。我无法在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]]
- 浅。
答案 0 :(得分:2)
许多Clojure核心库函数的一个重要特性是能够处理惰性(可能是无限的)序列;因此,我认为一个好的(惯用的)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)
尾部序列实际上是同一个对象。
答案 1 :(得分:1)
我确信还有其他方法可以做到这一点,但这是一种方式。
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
,因为filter
和remove
会返回列表,而不是向量。