【问题标题】:How to format string in Clojure by using map-indexed and vector如何使用 map-indexed 和 vector 在 Clojure 中格式化字符串
【发布时间】:2018-11-04 11:57:57
【问题描述】:

我正在尝试从以下格式的文件中读取内容:

ID|姓名|国家/地区名称|电话号码 例如:

1|Austin|Germany|34-554567
2|Mary Jane|Australia|45-78647

我正在使用以下代码从中获取数据:

(
  map-indexed
    #(vector %1 %2)
    (
      map #(vec(.split #"\|" %1))
      (
        line-seq (clojure.java.io/reader "test.txt")
      )
    )
)

使用此代码,我得到以下输出:

([0 ["1" "Austin" "Germany" "34-554567"]] [1 ["2" "Mary Jane" "Australia" "45-78647"]] [2 ["3" "King Kong" "New-Zealand" "35-467533"]])

我希望输出是这样的:

ID:["name" "country-name" "phone-number"]
ID:["name" "country-name" "phone-number"]

例如:

1:["Austin" "Germany" "34-554567"]
2:["Mary Jane" "Australia" "45-78647"]

其中ID要加1(从1、2、3等开始),每个结果都会列出身份或ID,后面是与ID结合的数据,并应按ID排序。

我要对我的代码进行哪些更改才能实现这一点?

【问题讨论】:

  • 你的意思是建立一个以ID为键的地图吗?试试(into {} your-output )
  • 看起来你问的和你得到的非常接近。
  • 是的,我正在尝试将文本文件中的 id 号分配给我得到的输出。所以最后我会很容易地对它们进行排序
  • @manandearth 实际上我现在得到的不适合我的实际输出。此外,我发现将所有内容分配为向量并使用索引获取每个值并不困难

标签: clojure functional-programming


【解决方案1】:

猜测:

(def data
  "1|Austin|Germany|34-554567
   2|Mary Jane|Australia|45-78647
   3|King Kong|New-Zealand|35-467533")

(->> (for [line (clojure.string/split data #"[ ]*[\r\n]+[ ]*")]
       (-> line (clojure.string/split #"\|") rest vec))
     (map vector (rest (range))))

; ([1 ["Austin" "Germany" "34-554567"]]
;  [2 ["Mary Jane" "Australia" "45-78647"]]
;  [3 ["King Kong" "New-Zealand" "35-467533"]])

虽然我不确定您为什么要在结果中显示明确的自动生成 ID,而忽略原始数据中的序列号。

可以选择在末尾添加(into (sorted-map)),这样您就可以将顺序 ID 映射到值,这与哈希映射不同,它保留了 ID 顺序。

【讨论】:

  • 您好@NikoNyrh,您能否用我的方式更新您的答案,因为我在从文本文件中获取数据并对其应用您提到的操作时遇到了一个小问题。
  • 您可以使用slurp 将文件内容作为字符串获取,至少在您使用绝对文件路径的情况下是这样。您描述的“输出”不是 Clojure 数据结构,因此它不能由 Clojure 函数产生。你想把它打印出来吗?也许您想将它插入intosorted-map
  • 你能告诉我如何获取 (([1 ["Austin" "Germany" "34-554567"]]) 的值,例如 a[1] 给出结果 1,a [2] 给出结果“Austin”等
  • 有一些函数可以从向量中获取元素,例如nthget。它们也可以作为“函数”运行,例如 (["Austin" "Germany" "34-554567"] 1) 的计算结果为 "Germany"
【解决方案2】:

您的数据中似乎已经有索引:

(def data
  "1|Austin|Germany|34-554567
   2|Mary Jane|Australia|45-78647
   3|King Kong|New-Zealand|35-467533 ")

(defn fmt [line]
  (let [sections (-> line
                     str/trim
                     (str/split #"\|")) ]
    sections) )

(defn run []
  (let [lines (vec (str/split-lines data)) ]
    (mapv fmt lines)))

(run)

结果:

sections => ["1" "Austin" "Germany" "34-554567"]
sections => ["2" "Mary Jane" "Australia" "45-78647"]
sections => ["3" "King Kong" "New-Zealand" "35-467533"]

如果你想丢弃数据中的索引,你可以像这样生成自己的:

(defn fmt [idx line]
  (let [sections      (-> line
                          str/trim
                          (str/split #"\|"))
        sections-keep (rest sections)
        result        (apply vector idx sections-keep)]
    result))

(defn run []
  (let [lines (vec (str/split-lines data))]
    (mapv fmt (range 1 1e9) lines)))

更新

如果要使用磁盘文件,请执行以下操作:

(def data
  "1|Austin|Germany|34-554567
   2|Mary Jane|Australia|45-78647
   3|King Kong|New-Zealand|35-467533 ")

(defn fmt [idx line]
  (let [sections      (-> line
                          str/trim
                          (str/split #"\|"))
        sections-keep (rest sections)
        result        (apply vector idx sections-keep)]
    result))

(defn run [filename]
  (let [lines (vec (str/split-lines (slurp filename)))]
    (mapv fmt (range 1 1e9) lines)))

(let [filename "/tmp/demo.txt"]
  (spit filename data)
  (run filename))

【讨论】:

  • 在您更新的答案中,这是我所理解的。您正在尝试将数据放入名为 demo.txt 的文件中,然后使用 slurp 读取该文件。在 fmt 函数中,您已经应用了修剪和拆分操作,然后在 run defn 中,您通过将 fmt 作为参数传递来映射向量。如果我错了,请纠正我。顺便说一句,我已经有一个从中读取数据的文件。是否需要创建一个新的,如 demo.txt 所示。事情在我头上蹦蹦跳跳。
  • 我只添加了spit 来显示文件的创建。如果你已经有一个,你显然不需要它。
【解决方案3】:

也许

(into {}  (map-indexed
       #(vector (inc %1) (rest %2))
       (repeat 2 ["1" "Austin" "Germany" "34-554567"])))

【讨论】:

    猜你喜欢
    • 2016-01-29
    • 1970-01-01
    • 2013-03-17
    • 1970-01-01
    • 2021-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    相关资源
    最近更新 更多