3

我有一张看起来像这样的地图:

user> (frequencies "aaabccddddee")
{\a 3, \b 1, \c 2, \d 4, \e 2}

而且我想要一个函数,它可以根据每个字符出现在我作为参数传递的字符串中的顺序对键/值对进行排序。

像这样的东西:

user> (somesort "defgcab" (frequencies "aaabccddddee"))
[[\d 4] [\e 2] [\c 2] [\a 3] [\b 1]]

(在上面的例子中,'f' 和 'g' 没有出现在映射中,因此它们被忽略了。保证字符串——在这个例子中是“defgcab”——应该包含映射中的每个字符/键)

只要对其进行排序,生成的集合就无关紧要。

我已经尝试了几件事,但找不到一种方法来完成这项工作。

4

4 回答 4

6

我更喜欢使用sort-by它来执行排序逻辑,并为您的集合创建一个自定义比较器:

(defn sorter [coll] (zipmap coll (range)))

(sort-by (comp (sorter "defgcab") key) 
         (frequencies "aaabccddddee"))

;=> ([\d 4] [\e 2] [\c 2] [\a 3] [\b 1])

编辑:这具有进一步的优势,您可以根据需要将收藏保留为地图,尽管您必须做更多的工作:

(defn map-sorter [coll]
  (let [order (zipmap coll (range))]
    (fn [a b]
      (compare (order a) (order b)))))

(into (sorted-map-by (map-sorter "defgcab"))
      (frequencies "aaabccddddee"))

;=> {\d 4, \e 2, \c 2, \a 3, \b 1}
于 2012-05-17T02:12:00.570 回答
2
(defn somesort [str st] 
    (filter (fn [[k v]] v ) (map (fn [c] [c (get st c)]) str)) )

这是如何工作的:

  • 对该字符串中的每个字符使用“排序字符串”上的映射,从集合中获取相应的键值作为向量
  • 使用filter,过滤掉值为nil的元素
于 2012-05-16T12:04:16.517 回答
2

Ankur 的解决方案用 表示for,这可能更容易阅读:

(defn somesort [str st] 
    (for [c str :let [v  (get st c)] :when v] [c v]))

假设自定义排序字符串中的字符是唯一的,则此方法有效。

排序字符串被迭代一次,它的每个字符都在地图中查找。如果您确保传递给函数的映射是哈希映射,那么这是线性的。

于 2012-05-16T13:27:04.340 回答
1

您还可以使用whichfind返回: [k v]map

(let [fs (frequencies "abbccc")]
  (map #(find fs %) "defgcab")
于 2012-05-16T14:06:57.727 回答