【问题标题】:Implement reversing a sequence in a way that is idiomatic for Clojure以 Clojure 惯用的方式实现反转序列
【发布时间】:2014-04-14 19:19:33
【问题描述】:

任务是编写一个反转序列的函数。我正在尝试尽可能有效地和 clojure-ish 做到这一点,但我想不出最好的方法。创建一个变量并开始将项目附加到该变量是不对的。如果有办法做到以下几点,对我来说似乎是惯用的:

来自 Clojure 文档

(map-indexed (fn [idx itm] [idx itm]) "foobar")
--> ([0 \f] [1 \o] [2 \o] [3 \b] [4 \a] [5 \r])

我所做的是这样的:

(defn testing [x]
(map-indexed (fn [idx itm] [(- (count x) idx) itm]) x))

产量:

(testing "foobar")
--> ([6 \f] [5 \o] [4 \o] [3 \b] [2 \a] [1 \r])

我想不通的是如何从本质上将其打包到具有正确索引的新列表中。老实说,目前在 Clojure 中,即使是声明变量的概念也让我无法理解。我所有的经验都是使用 Python 和 Ruby。

【问题讨论】:

  • 你可以在clojuredocs.org/clojure_core/clojure.core/reverse#source找到reverse的源代码。
  • 我可以建议您将问题重新命名为“以 Clojure 惯用的方式实现反转序列”。通常,返回序列的惯用方式通常是惰性的,但对于这个问题,情况并非如此。

标签: clojure


【解决方案1】:

字符串是可排序的,所以我们可以使用clojure.core/reduce

(defn rev [x]
  (reduce #(str %2 %1) x))

(rev "foobar") ;; "raboof"

我们的想法是,对于每次迭代,我们都会创建一个新字符串,该字符串是当前字符串前面的序列中的下一个字符。

我所有的经验都是使用 Python 和 Ruby

Ruby这里也是一样的:

def rev(x)
  x.chars.reduce { |s, c| c + s }
end

对于非字符串

(defn rev [x]
  (reduce conj () x))

(rev [1 2 3 4 5]) ;; (5 4 3 2 1)

【讨论】:

  • 优秀。非常感谢!我知道这是一件很简单的事情,即使我在这里用头撞墙。
  • 实际上@Kyle,由于某种原因,我在使用不是字符串的 seq 时遇到了同样的麻烦。有什么想法吗?
  • @Borromakot 我为非字符串添加了一个解决方案。如果您要将它与字符串一起使用,您可能需要 (apply str (rev "foobar")) 以获取字符串作为输出。
  • 谢谢!好东西。我在看完全错误的地方。我曾假设我只是想将两者联系起来,使用 concat 或 conj 或类似的东西。甚至不知道缺点。再次感谢!
【解决方案2】:

您可以按照您的问题建议使用索引来反转序列,如下所示:

(defn reverse [s]
  (let [v (vec s)] (map v (range (dec (count v)) -1 -1))))

...或者,反常地,

(def reverse (comp rseq vec))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-05
    • 1970-01-01
    • 2013-04-22
    • 2014-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-19
    相关资源
    最近更新 更多