为什么 clojure 核心库不支持索引函数?
Why doesn't clojure core library support an index-of function?
最近,我开始学习 clojure 编程和一般的函数式编程。在解决一些基本的编程难题时,我注意到的一件事是向量没有索引函数,例如。核心功能没有反转 nth
。我见过人们自己实现它或使用一些 java 替代实现。
我的问题不是是否有解决方法(但如果您知道一个特别优雅的解决方法,请分享),因为我知道有。我想知道的是:为什么会这样,例如。为什么 clojure 开发人员决定不实施看似如此基本的操作。在 clojure 中以某种方式在向量中进行位置查找是不是惯用的,并且理想情况下会以其他方式完成吗?怎么样?
以相反的顺序回答两个问题:
"Workaround":clojure 中的 vector
实现了 java.util.List
,因此 java 工作简单(足够优雅,imo)
(.indexOf [1 2 3] 2)
1
此外,字符串可以利用clojure.string/index-of
为什么不在clojure.core中:这相当于一个问题"why there's no [a polymorphic fn] for various collection types",在这里回答:https://clojure.org/guides/faq#conj and here https://gist.github.com/reborg/dc8b0c96c397a56668905e2767fd697f#why-clojure-doesnt-have-a-generic-insert-lookup-append-that-works-the-same-on-all-collections
是一个标准的 Clojure 函数,它几乎可以满足问题的要求。
如果我们查看 the skeleton source,我们需要做的是反转序列,例如...
(def ranks [2 3 4 5 6 7 8 9 10 :jack :queen :king :ace])
... 到地图(或其他函数)中,为我们提供 每个 值的索引:
{7 5, :king 11, 4 2, :queen 10, :ace 12, 6 4, 3 1, 2 0, :jack 9, 9 7, 5 3, 10 8, 8 6}
我们可以一劳永逸。
几乎可以做到这一点的标准函数是clojure.set/map-invert
。
- 但它适用于地图,不适用于序列。
- 但它将它们视为成对序列。
因此,将向量(或其他序列)反转为索引函数的简单函数是...
(defn indexes-of [v]
(->> v
(map-indexed vector)
(clojure.set/map-invert)))
例如,
(indexes-of ranks)
=> {7 5, :king 11, 4 2, :queen 10, :ace 12, 6 4, 3 1, 2 0, :jack 9, 9 7, 5 3, 10 8, 8 6}
因此,那些说您的想法错误的人是正确的。
然而,在 Clojure 本身内执行这样的无域计算肯定更好,但是 Clojure 可以顺利地与它恰好在 运行 上的任何 VM 对接。
我们需要的是一个斗篷来覆盖矢量以使其成为地图:就像 rseq
将斗篷覆盖在矢量上一样,使它看起来像一个相反的序列。然后我们不需要假设 map-invert
将接受一个对序列。 (现在为了安全起见,我们可以为 into
对序列提供一个映射以提供给 map-invert
)。
最近,我开始学习 clojure 编程和一般的函数式编程。在解决一些基本的编程难题时,我注意到的一件事是向量没有索引函数,例如。核心功能没有反转 nth
。我见过人们自己实现它或使用一些 java 替代实现。
我的问题不是是否有解决方法(但如果您知道一个特别优雅的解决方法,请分享),因为我知道有。我想知道的是:为什么会这样,例如。为什么 clojure 开发人员决定不实施看似如此基本的操作。在 clojure 中以某种方式在向量中进行位置查找是不是惯用的,并且理想情况下会以其他方式完成吗?怎么样?
以相反的顺序回答两个问题:
"Workaround":clojure 中的 vector
实现了 java.util.List
,因此 java 工作简单(足够优雅,imo)
(.indexOf [1 2 3] 2)
1
此外,字符串可以利用clojure.string/index-of
为什么不在clojure.core中:这相当于一个问题"why there's no [a polymorphic fn] for various collection types",在这里回答:https://clojure.org/guides/faq#conj and here https://gist.github.com/reborg/dc8b0c96c397a56668905e2767fd697f#why-clojure-doesnt-have-a-generic-insert-lookup-append-that-works-the-same-on-all-collections
是一个标准的 Clojure 函数,它几乎可以满足问题的要求。
如果我们查看 the skeleton source,我们需要做的是反转序列,例如...
(def ranks [2 3 4 5 6 7 8 9 10 :jack :queen :king :ace])
... 到地图(或其他函数)中,为我们提供 每个 值的索引:
{7 5, :king 11, 4 2, :queen 10, :ace 12, 6 4, 3 1, 2 0, :jack 9, 9 7, 5 3, 10 8, 8 6}
我们可以一劳永逸。
几乎可以做到这一点的标准函数是clojure.set/map-invert
。
- 但它适用于地图,不适用于序列。
- 但它将它们视为成对序列。
因此,将向量(或其他序列)反转为索引函数的简单函数是...
(defn indexes-of [v]
(->> v
(map-indexed vector)
(clojure.set/map-invert)))
例如,
(indexes-of ranks)
=> {7 5, :king 11, 4 2, :queen 10, :ace 12, 6 4, 3 1, 2 0, :jack 9, 9 7, 5 3, 10 8, 8 6}
因此,那些说您的想法错误的人是正确的。 然而,在 Clojure 本身内执行这样的无域计算肯定更好,但是 Clojure 可以顺利地与它恰好在 运行 上的任何 VM 对接。
我们需要的是一个斗篷来覆盖矢量以使其成为地图:就像 rseq
将斗篷覆盖在矢量上一样,使它看起来像一个相反的序列。然后我们不需要假设 map-invert
将接受一个对序列。 (现在为了安全起见,我们可以为 into
对序列提供一个映射以提供给 map-invert
)。