【问题标题】:Convert a list with to distinct regions into a Map将具有不同区域的列表转换为地图
【发布时间】:2015-06-14 07:00:40
【问题描述】:

转换这种形式的列表:

 ( arg1  arg2 ... :first_keyword val_1 :key2 val_2 ... )

进入这张地图:

 { 1 arg1, 2 arg2, ..., :first_keyword val_1, :key2 val_2, ... }

我可以看到非常丑陋的方法来做到这一点。但是 Clojure 的方法是什么?

  .
  .
  .

(P.S. 我对 Clojure 的早期反应是感觉有点像 针对更多“类似玩具”的任务进行了优化。如果连接您的输入的逻辑 并且输出上有任何头发,然后我觉得我花了更多的钱 努力与语言而不是问题作斗争。具体来说, 跟踪你的'recurs'语句中的第五个参数感觉 就像我在做编译器应该做的事情...... 但也许我的 Clojure 眼光还是太弱了……)

【问题讨论】:

  • 我认为 Clojure 一点也不像玩具。这不一样。函数式编程需要转变思维,学习使用 Clojure 提供的便利需要一些时间来适应。但我说这不是你同意的理由。您可能会发现即使有经验也不舒服。我不认为 Clojure 适合每个人,也不是适合所有任务。 (我确实认为 Clojure 在这个意义上是“玩具般的”:imo,它让很多事情变得更容易——也更有趣——比在 Java 中。这让 Java 感觉更“严肃”——但不是更好。其他人会不同意。)
  • 这并不是说 Closure 看起来像玩具,而是它可以优雅地解决的问题似乎是有限的。总是可以创建一个包含所有局部变量的循环,然后使用大量的 recurs 语句来更新所有局部变量,但这感觉就像我们在给程序员 w 带来负担。不必要的复杂性。 Closure 有数百种非常特殊的方法,例如 split-with 来避免这种情况,但它开始感觉像是在尝试用俳句写一篇新闻文章。 (当然,如果你能做到,那我想它确实证明了你的才华!)无论如何,谢谢!
  • “它可以优雅地解决的问题似乎可能有限”:也许这是真的,对于那些对你来说很突出的问题,以及你的优雅感——或者也许有更多的经验你会改变你的想法。谁知道?其他人肯定不同意。我对 Clojure 没有这种感觉。我很遗憾我不能在 Clojure 中完成所有的编码。我确实认为纯函数式、无副作用的编程既有优点也有缺点,在 Clojure 中使用副作用需要额外的编码(原子等)或额外的小心。不过,我并不像我想象的那样需要副作用。
  • 关于您的 P.S. ...将导致您花费更多精力与语言而不是问题作斗争的问题作为问题,看看您得到什么答案。谁知道。也许你是对的。但不得不说,我的经历恰恰相反。
  • @thumbnail,我喜欢同音语言,我认为功能性“上层建筑”值得约束。但是让可变的局部变量变得如此令人眼花缭乱和痛苦(并且表现不佳)似乎是一个巨大的损失。似乎有 100 种不同的循环可以帮助我在 for 循环中编写不带局部变量的程序。对于这一决定,我没有看到在复杂性、速度、安全性等方面的节省。(我很乐意将我的 PS 作为一个问题发布,但 StackOverflow 不喜欢这类问题。)感谢您的帮助!

标签: clojure idioms


【解决方案1】:
(loop [inputs ["arg1" "arg2" :key1 1 :key2 2] index 1 output {}]
  (if (empty? inputs) output
    (let [input (first inputs) rest-inputs (rest inputs)]
      (if (keyword? input)
        (recur (rest rest-inputs) index (assoc output input (second inputs)))
        (recur rest-inputs (inc index) (assoc output index input))))))

您可以使用 for 理解或 reduce 进行一些预处理,但在这种情况下循环可能是最干净的。

【讨论】:

  • 感谢 Optevo,我认为我的问题规范不明确。目标是将第一个关键字之后的所有对视为键/值对。我认为您的代码仍然允许在第一个关键字之后使用固定参数。但我不认为我这么清楚。
【解决方案2】:

这里有一个解决方案:

(let [[vals keyvals]
      (split-with (complement keyword?) 
                  [100 101 102 :a 103 :b 104 :c 105])]
  (merge (zipmap (range) vals) 
         (apply hash-map keyvals)))

=> {:a 103, :b 104, :c 105, 2 102, 1 101, 0 100}

这使得 0 成为第一个元素的键。如果您想要基于 1 的密钥,您可以将 (range) 包装在 (map inc _) 中。

其他说明:

(split-with (complement keyword?) ...) 将序列分成两部分:没有关键字的序列,以及其余部分。

(zipmap (range) vals) 将两个序列“压缩”成一个映射,使用来自range 的整数与vals 一样多。

【讨论】:

  • 要从1 开始,请使用(rest (range))
  • 啊,好多了。谢谢@Thumbnail。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-01
  • 1970-01-01
  • 2019-05-10
  • 1970-01-01
  • 2020-07-06
  • 1970-01-01
相关资源
最近更新 更多