【问题标题】:Partition a number sequence in clojure在clojure中对数字序列进行分区
【发布时间】:2011-05-01 13:20:15
【问题描述】:

我有以下输入:

(def nums [123456789012 123456789012])

我想要以下输出:

[[1234 5678 9012] [1234 5678 9012]]

*注意这两个序列都包含数字而不是字符串...

我认为通过执行以下操作会非常简单:

  1. 将每个条目转换为字符串
  2. 将每个字符串分割为 4
  3. 将每个分区转换回整数

这是我失败的尝试:

(defn split-nums [nums factor]
  (map
    #(map
       (fn [x] (Integer/valueOf (str x)))
       (partition factor (str %)))
  nums))

(println (split-nums nums, 4))

当我运行它时,我收到以下错误:

Caused by: java.lang.NumberFormatException: For input string: "clojure.lang.LazySeq@4834333c"

这告诉我我正在处理一个需要强制评估的惰性序列,但是当我尝试 (str (doall x)) 时,我得到了相同的结果。

那么 clojure 专家我哪里错了?这是一个好方法吗?顺便提一句。我刚开始学习clojure,所以我当然不是专家。

【问题讨论】:

  • 另外,当我转换回整数时,我确信我需要处理可能的前导零,但我认为这不会太难修复:-)
  • 哇! stackoverflow clojure 社区很棒。很多好的答案,我现在也看到了我的愚蠢错误和一些更好的想法。我会在尝试后不久投票。

标签: clojure


【解决方案1】:
(defn split-nums [nums factor]
  (map #(map (fn [x] (Integer/valueOf (apply str x))) ; apply str
             (partition factor (str %)))
       nums))

(str (lazy-seq [1])) ; "clojure.lang.LazySeq@20"

(apply str (lazy-seq [1])) ; "1"


我可能会写它来接受一个数字,然后使用 map,而不是使用 coll。

(defn split-number [n factor]
  (->> (str n)
       (partition-all factor) ;; or partition
       (map (partial apply str))
       (map #(Integer/valueOf %))))

(map #(split-number % 4) [12345678 12345678]) ;; => ((1234 5678) (1234 5678))


如果您更愿意使用整数而不是字符串:

(mod 5151 10) ;; => 1 获取最低有效数字。

(/ 5151 10) ;; => 515 删除最低有效数字。

【讨论】:

  • 感谢您指出我出错的确切位置 - 将序列串在一起,而不是将序列中的每个元素串在一起产生一个新字符串。另外,我同意您使该方法接受单个数字的想法。我仍然习惯于其他处理集合的方式不太强大/简洁的语言。最后,是的,直接处理数字而不是进行转换可能更好。
【解决方案2】:
(def nums [123456789012 123456789012])

(defn part-int [l n] 
  (map #(Integer. (apply str %)) 
    (partition l (str n))))

(map (partial part-int 4) nums)
;; => ((1234 5678 9012) (1234 5678 9012))

【讨论】:

    【解决方案3】:

    在这种情况下,我认为 for 真的很好用。你没有那么多地图。

    (def nums [123456789012 123456789012])
    
    (for [num nums] 
        (map #(Integer. (apply str %)) 
              (partition 4 (str num))))
    ;; => ((1234 5678 9012) (1234 5678 9012))
    

    【讨论】:

    • 你有一个额外的关闭参数 - 很容易做到。否则工作正常。
    【解决方案4】:

    @nickik 对上述解决方案的轻微变化

    (partition 3
      (map #(Integer. (apply str %))
           (partition 4 
             (apply concat (map str nums)))))
    

    【讨论】:

    • (apply concat (map ...)) = (mapcat ...)
    • 您的解决方案实际上更灵活一些,因为您正在执行两个分区,因此您可以轻松地使代码生成 [[1234 5678] [9012 1234] [5678 9012]] 这不是其中之一我的要求,但仍然很有趣。
    【解决方案5】:

    为什么要先转换成字符串?这是带有/mod 的版本。这也将解决您的前导零问题。

    (defn int-partition [num size]
       (let [f (int (Math/pow 10 size))]
          (loop [n num l ()]
             (if (zero? n) 
                (vec l) 
                (recur (int (/ n f)) (conj l (mod n f)))))))
    
    (defn split-nums [nums factor] (vec (map #(int-partition % factor) nums)))
    

    【讨论】:

      【解决方案6】:
      user=> (map #(->> % (str) (partition 4) (map (fn [s] (read-string (apply str s))))) nums)
      ((1234 5678 9012) (1234 5678 9012))
      

      最好是提取函数。

      【讨论】:

      • read-string 比使用 Integer 慢十倍以上。或 Integer/parseInt 或 Integer/valueOf 等。
      • 有效,但在前导零方面确实存在问题。如果输入是 [123406789012 123406789012] 它将失败。感谢您提供替代解决方案。
      猜你喜欢
      • 1970-01-01
      • 2012-09-30
      • 2020-09-20
      • 2015-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-28
      相关资源
      最近更新 更多