【问题标题】:Clojure: sort-by nested map custom comparatorClojure:按嵌套映射自定义比较器排序
【发布时间】:2017-10-30 17:50:44
【问题描述】:

我有一个嵌套的 Clojure 映射:

{
  :1 {
    :priority "Medicore"
    :somekey "SomeValue"
  },
  :2 {
    :priority "Enormous"
    :somekey "SomeValue"
  },
  :3 {
    :priority "Weeny"
    :somekey "SomeValue"
  }
}

我的目标是从具有“最高”优先级的地图中获取somekey 的值。外部映射可以包含 0-n 个具有三个优先级中的任何一个的元素。如果有多个具有最高可用优先级的条目,我可以选择任何一个。

在研究了其他一些 SO 问题后,我认为解决此问题的一个好方法是使用 sort-by 函数。但由于我的priority 不是自然排序的,我必须提供一些自定义比较器。

这可能吗?我的方法是否适合我的目标?

【问题讨论】:

    标签: sorting clojure


    【解决方案1】:

    要使用sort-by,您需要提供排序或您的优先级值。您可以实现自定义比较器来比较您的地图或为 sort-by 定义一个 keyfn 来计算用于排序的键。 keyfn 的解决方案如下。仅使用 keyfn 返回符合您要求的可比较值比实现比较器要容易得多。你可能想看看Comparators Guide

    我们开始定义一个函数来将字符串优先级转换为它的数字表示:

    (let [priorities {"Medicore" 0
                      "Enormous" 1
                      "Weeny"    2}]
      (defn priority->num [p]
        (if-let [num (priorities p)]
          num
          (throw (IllegalArgumentException. (str "Unknown priority: " p))))))
    
    (priority->num "Enormous")
    ;; => 1
    

    现在我们需要计算每个地图的最大优先级:

    (defn max-priority-num [m]
      (->> m
           (vals)
           (map (comp priority->num :priority))
           (apply max)))
    
    (max-priority-num {:1 {:priority "Medicore" :somekey "SomeValue"}
                       :2 {:priority "Enormous" :somekey "SomeValue"}
                       :3 {:priority "Weeny"    :somekey "SomeValue"}})
    ;; => 2
    

    现在我们终于可以使用sort-by了:

    (def m1 {:1 {:priority "Medicore" :somekey "SomeValue"}
             :2 {:priority "Medicore" :somekey "SomeValue"}
             :3 {:priority "Weeny"    :somekey "SomeValue"}})
    
    (def m2 {:1 {:priority "Medicore" :somekey "SomeValue"}
             :2 {:priority "Enormous" :somekey "SomeValue"}
             :3 {:priority "Weeny"    :somekey "SomeValue"}})
    
    (def m3 {:1 {:priority "Medicore" :somekey "SomeValue"}
             :2 {:priority "Medicore" :somekey "SomeValue"}
             :3 {:priority "Medicore" :somekey "SomeValue"}})
    
    (sort-by max-priority-num [m1 m2 m3])
    ;; =>
    ({:1 {:priority "Medicore", :somekey "SomeValue"},
      :2 {:priority "Medicore", :somekey "SomeValue"},
      :3 {:priority "Medicore", :somekey "SomeValue"}}
     {:1 {:priority "Medicore", :somekey "SomeValue"},
      :2 {:priority "Medicore", :somekey "SomeValue"},
      :3 {:priority "Weeny", :somekey "SomeValue"}}
     {:1 {:priority "Medicore", :somekey "SomeValue"},
      :2 {:priority "Enormous", :somekey "SomeValue"},
      :3 {:priority "Weeny", :somekey "SomeValue"}})
    

    【讨论】:

    • 使用max-key 比使用sort-by 更容易。
    • 对@amalloy,我忽略了OP想要获得最大元素,而不是所有元素都排序!所以与其调用(sort-by max-priority-num [m1 m2 m3])(max-key max-priority-num m1 m2 m3)(apply max-key max-priority-num maps) 会更好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多