【问题标题】:Clojure: easily convert from invalid string to valid keywordClojure:轻松从无效字符串转换为有效关键字
【发布时间】:2014-01-23 16:00:06
【问题描述】:

我一直在尝试找到一种惯用的方式将用户数据转换为 clojure 中的有效关键字。

一个可能的用例是在阅读 excel 电子表格时,我想为除了第一行之外的每一行动态构建一个映射,其中第一行包含将成为关键字的标题。我需要考虑可能包含空格或其他无效字符的标题。我已经读过关键字函数不会抱怨,并且会给你一个可能难以使用甚至有害的无效密钥。

我可以手动进行转换,或者可能使用像 slgger 这样的框架来执行此操作,但我想知道是否有任何内置的东西可以处理这个问题。

另外,我读到过创建太多键可能会使堆过载,但那是从 2010 年开始的,它可能已在 1.3 中解决。用字符串键而不是关键字创建我的哈希映射对我来说最好吗?我已经读过这样做不是惯用的。

【问题讨论】:

  • 是否有充分的理由将带有违规字符的字符串用作键而不是转换为关键字?似乎您可以避免整个问题并保持键与列名相同。
  • 正如下面所说的过度思考,它不会抱怨空格,因此(关键字“hi there”)被转换为 :hi there,因为你不能直接调用它,所以这不容易使用,你必须始终使用(关键字“hi there”),:hi there 抛出运行时异常
  • 序列化和重新加载字符串是一个已解决的问题,与为每个字符串制作可读关键字的繁琐工作相比,制作关键字关键字是一个很小的好处。除非你不需要序列化!如果您不打算存储和重新加载关键字,那么只需从字符串中创建关键字。 (keyword "this is a string") 完全有效,只是在其默认打印形式下不可读。
  • 要明确:带空格的关键字无效。没事。它只是不可读。
  • 在空格的情况下你是对的,但是关键字允许我也可能遇到的无效字符,比如 % soace 是我可能遇到的一个例子,但它甚至很难使用如果它可能是有效的。我一直倾向于使用“增加百分比”并将其转换为“增加百分比”的重击手,这将成为一个有效的密钥,但我想确保我没有重新发明轮子。

标签: clojure


【解决方案1】:

除非您有充分的理由这样做,否则只需使用字符串本身作为键。

user=> (def my-db (atom {}))
#'user/my-db
user=> (swap! my-db assoc "New York" 1)
{"New York" 1}
user=> (swap! my-db assoc "Los Angeles" 2)
{"Los Angeles" 2, "New York" 1}
user=> (do (print "Which city do you want to rank?\n =>") 
           (flush) 
           (@my-db (read-line)))
Which city do you want to rank?
 =>New York
1

如果您对地图进行编码/关键字化,则必须在每次与用户约定的交互时进行编码/关键字化或字符串化/解码。

【讨论】:

  • 除了不能使用键作为函数从映射中检索值之外,使用字符串作为键还有哪些其他缺点?关键字可以充当函数,因此 (:key my-map) 返回与 :key 关联的值,但 ("key" my-map) 会抛出异常。相反,我必须编写它(我的地图“键”)来检索值。这最初似乎不是问题,但在关键字可以充当部分函数的地方,它可能会变得更加令人头疼。 (地图:关键地图列表)。我希望我不会太挑剔,我还是 clojure 的新手。这可能是我由于解码而采取的路线
  • 就头痛而言,(map #(get % "string") list-of-maps) 似乎比您建议的要温和得多。
  • 如果我没记错的话,map中的字符串都是分开存储的,如果重复的话可能会导致内存问题。关键字不会受此影响,因为它们是被实习的。
  • @NielsK 字符串字面量被实习生(identical? "hello" "hello") => true。任意字符串数据不是(identical? "hello" (str "hell" "o")) => false。这可能就是你想要的。但是,如果需要,任何字符串都可以被实习(identical? "hello" (.intern (str "hell" "o"))) => true
【解决方案2】:

嗯,keyword 似乎会吐出不可读的关键字:

user=> (keyword "foo bar")
:foo bar
user=> (keyword "foo:")
:foo:

这些都不能再次读入。

我只需要编写一个小函数来清理您的输入(规则 here),然后再将其传递给 keyword 函数。

【讨论】:

  • Symbol 也有同样的行为:(eval `(def ~(symbol "#") "yikes!"))
  • 我会称之为,至少第二个:foo: 和上面的#,无效但未强制执行。
猜你喜欢
  • 2020-02-22
  • 1970-01-01
  • 2011-04-12
  • 1970-01-01
  • 2014-07-26
  • 2016-03-10
  • 1970-01-01
  • 1970-01-01
  • 2013-02-09
相关资源
最近更新 更多