根据自定义比较器排序

时间:2012-05-16 11:52:37

标签: sorting map vector clojure

我的地图看起来像这样:

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 个答案:

答案 0 :(得分: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}

答案 1 :(得分:2)

(defn somesort [str st] 
    (filter (fn [[k v]] v ) (map (fn [c] [c (get st c)]) str)) )

这是如何运作的:

  • 在该字符串中的每个字符的“排序字符串”上使用map,从集合中获取相应的键值作为向量
  • 使用过滤器,过滤掉值为nil
  • 的元素

答案 2 :(得分:2)

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

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

这可以假设自定义排序字符串中的字符是唯一的。

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

答案 3 :(得分:1)

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

(let [fs (frequencies "abbccc")]
  (map #(find fs %) "defgcab")