Clojure Core 或 Contrib 中的 Zip 函数是不是有等价物?

Posted

技术标签:

【中文标题】Clojure Core 或 Contrib 中的 Zip 函数是不是有等价物?【英文标题】:Is there an equivalent for the Zip function in Clojure Core or Contrib?Clojure Core 或 Contrib 中的 Zip 函数是否有等价物? 【发布时间】:2011-02-05 00:06:06 【问题描述】:

在 Clojure 中,我想组合两个列表来给出一个对的列表,

> (zip '(1 2 3) '(4 5 6))  
((1 4) (2 5) (3 6))

在 Haskell 或 Ruby 中,该函数称为 zip。实现它并不难,但我想确保我没有遗漏 Core 或 Contrib 中的功能。

Core 中有一个 zip 命名空间,但它是 described 提供对 Zipper 功能技术的访问,这似乎不是我所追求的。

在 Core 中是否有以这种方式组合 2 个或更多列表的等效功能?

如果没有,是不是因为有一种惯用的方法使函数变得不需要?

【问题讨论】:

Tupelo 库中有一个zip 函数:cloojure.github.io/doc/tupelo/tupelo.core.html#var-zip 【参考方案1】:
(map vector '(1 2 3) '(4 5 6))

做你想做的事:

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

Haskell 需要一个 zipWith (zipWith3, zipWith4, ...) 函数的集合,因为它们都需要是特定的类型;特别是,他们接受的输入列表的数量需要固定。 (zip, zip2, zip3, ... 系列可以看作是 zipWith 系列的特化,用于元组的常见用例。

相比之下,Clojure 和其他 Lisps 对可变参数函数有很好的支持; map 是其中之一,可用于“元组”,其方式类似于 Haskell 的

zipWith (\x y -> (x, y))

在 Clojure 中构建“元组”的惯用方式是构建一个短向量,如上所示。

(为了完整起见,请注意带有一些基本扩展的 Haskell 确实允许可变 arity 函数;不过,使用它们需要对语言有很好的理解,而 vanilla Haskell 98 可能根本不支持它们,因此固定了 arity函数更适合标准库。)

【讨论】:

请注意,当集合长度不同时,这与 zip 的行为不同。 Ruby 将继续处理并为较短的集合提供 nils,而 Clojure 将在其中一个集合用完后停止处理。 @NateW。这是很好的注意,谢谢。在 Haskell 中,zip 在这方面的行为类似于 Clojure 的 map 我可以要求提供关于变量 arity Haskell 函数的参考吗?【参考方案2】:
(partition 2 (interleave '(1 2 3) '(4 5 6))) 
=> ((1 4) (2 5) (3 6))

或更一般地

(defn zip [& colls]
  (partition (count colls) (apply interleave colls)))

(zip '( 1 2 3) '(4 5 6))           ;=> ((1 4) (2 5) (3 6))

(zip '( 1 2 3) '(4 5 6) '(2 4 8))  ;=> ((1 4 2) (2 5 4) (3 6 8))

【讨论】:

【参考方案3】:
(map vector [1 2 3] [4 5 6])

【讨论】:

【参考方案4】:

为了提供您想要的准确信息,在两个列表之间映射 list 将为您提供一个列表列表,如您的示例中所示。我认为许多 Clo​​jurian 会倾向于为此使用向量,尽管它适用于任何东西。并且输入不需要是相同的类型。 map 从它们创建序列,然后映射序列,因此任何可序列化的输入都可以正常工作。

(map list '(1 2 3) '(4 5 6))
(map list  [1 2 3] '(4 5 6))
(map hash-map  '(1 2 3) '(4 5 6))
(map hash-set  '(1 2 3) '(4 5 6))

【讨论】:

我认为你的意思是 hash-map 和 hash-set 而不是 map 和 set。【参考方案5】:

内置方式就是函数'interleave':

(interleave [1 2 3 4] [5 6 7 8]) => [1 5 2 6 3 7 4 8]

【讨论】:

要实现OP的目标你应该添加(partition 2 (interleave [1 2 3 4][5 6 7 8])) 是的 - 看来我没有仔细查看 OP 的期望输出。【参考方案6】:

有一个函数叫做 zipmap,可能有类似的效果, (zipmap(1 2 3)(4 5 6)) 输出如下: 3 6、2 5、1 4

【讨论】:

zipmap返回给你一张地图,不保证顺序 这也是我的第一个想法。不错的尝试。【参考方案7】:

#(apply map list %) 转置矩阵,就像 Python zip* 函数一样。作为一个宏定义:

user=> (defmacro py-zip [lst] `(apply map list ~lst))

#'user/py-zip

user=> (py-zip '((1 2 3 4) (9 9 9 9) (5 6 7 8)))

((1 9 5) (2 9 6) (3 9 7) (4 9 8))

user=> (py-zip '((1 9 5) (2 9 6) (3 9 7) (4 9 8)))

((1 2 3 4) (9 9 9 9) (5 6 7 8))

【讨论】:

这比只使用“地图”有什么好处?宏的意义何在?

以上是关于Clojure Core 或 Contrib 中的 Zip 函数是不是有等价物?的主要内容,如果未能解决你的问题,请参考以下文章

Clojure 中的速率限制 core.async 通道

clojure 中的分析(用于大型代码)

Clojure 中的循环负载依赖关系

Clojure core.logic 中的阶乘

什么是惯用的clojure:使用

Clojure中的Dijkstra&ŧ039;s算法