How to rewrite Ruby's `Array(x)` in Clojure?
在Ruby中,有一个
1 2 3 4 | Array([1, 2, 3]) #=> [1, 2, 3] Array(1..5) #=> [1, 2, 3, 4, 5] Array(9000) #=> [9000] Array(nil) #=> [] |
换句话说,它将nil转换为空数组,将非集合转换为单例数组,并将各种类似于集合的对象(即响应
我想在Clojure中有类似的东西:
1 2 3 4 | (to-seq [1 2 3]) ;=> (1 2 3) (to-seq (range 1 5)) ;=> (1 2 3 4) (to-seq 9000) ;=> (9000) (to-seq nil) ;=> nil; () is ok too |
到目前为止,这就是我得到的:
1 | (defn to-seq [x] (if (seqable? x) (seq x) '(x))) |
但我不喜欢它,因为:
1 | (for [person (to-seq person-or-people)] ...) |
因此,如果将其作为矢量-可以。如果它将是向量,Java数组,列表或nil(取决于输入),也可以。
==== UPD ====
几乎是最终版本:
1 | (defn to-seq [x] (if (or (nil? x) (coll? x)) x [x])) |
最终版本:
<罢工>
strike>
我不需要序列,它看起来没有吸引力。
如果只需要遍历输入,并且实际上它是某种容器,则通常不需要执行任何特殊的转换。想到的两个特殊情况由
话虽如此,我相信内核中实际上没有现成的函数来确定对象是否是
当然,总是有可能尝试应用
1 2 3 4 5 6 7 | (defn seq-at-all-costs [x] (try (seq x) (catch IllegalArgumentException e (list x)))) ; NB. '(x) wouldn't work, since it would ; cause a literal symbol x to be returned, ; as noted in my comment on the question |
您也可以执行以下操作来加快速度(希望-我一定会进行基准测试):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | (defprotocol IKnowHowToSeqYou (seq-knowledgeably [this])) (defn seq! [x] (try (seq-knowledgeably x) (catch IllegalArgumentException e (try (seq x) (extend-type (class x) IKnowHowToSeqYou (seq-knowledgeably [this] (seq this))) (catch IllegalArgumentException e (extend-type (class x) IKnowHowToSeqYou (seq-knowledgeably [this] (list this))))) (seq-knowledgeably x)))) |
但是,我不得不说,我几乎从未(也许实际上从未)感到需要
这是到目前为止
如果输入已经是一个序列(对
如果是延迟序列,则将其强制执行并返回结果;
否则,如果它实现
如果恰好是
如果它是
如果是数组,则返回数组seq;
如果它是
如果它是
否则将引发异常。
1 2 3 4 | (map coll? [() [] #{} {} 1"sandwich" :a nil])) ;=> (true true true true false false false false) (defn to-seq [x] (if (coll? x) (seq x) (list x))) |
另请参阅: