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 将继续处理并为较短的集合提供 nil
s,而 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
将为您提供一个列表列表,如您的示例中所示。我认为许多 Clojurian 会倾向于为此使用向量,尽管它适用于任何东西。并且输入不需要是相同的类型。 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 函数是不是有等价物?的主要内容,如果未能解决你的问题,请参考以下文章