使用clojure,是否有更好的方法从序列中删除项目,即地图中的值?

如何解决使用clojure,是否有更好的方法从序列中删除项目,即地图中的值?

一个包含序列的地图。序列包含项目。 我想从包含它的任何序列中删除给定的项目。

我找到的解决方案做了它应该做的,但我想知道是否有更好的 或更优雅的方式来实现相同的目标。

我目前的解决方案:

(defn remove-item-from-map-value [my-map item]
    (apply merge (for [[k v] my-map] {k (remove #(= item %) v)})))

测试描述了预期的行为:

(require '[clojure.test :as t])

(def my-map {:keyOne   ["itemOne"]
             :keyTwo   ["itemTwo" "itemThree"]
             :keyThree ["itemFour" "itemFive" "itemSix"]})

(defn remove-item-from-map-value [my-map item]
  (apply merge (for [[k v] my-map] {k (remove #(= item %) v)})))

(t/is (= (remove-item-from-map-value my-map "unkNown-item") my-map))
(t/is (= (remove-item-from-map-value my-map "itemFive") {:keyOne   ["itemOne"]
                                                         :keyTwo   ["itemTwo" "itemThree"]
                                                         :keyThree ["itemFour" "itemSix"]}))

(t/is (= (remove-item-from-map-value my-map "itemThree") {:keyOne   ["itemOne"]
                                                          :keyTwo   ["itemTwo"]
                                                          :keyThree ["itemFour" "itemFive" "itemSix"]}))

(t/is (= (remove-item-from-map-value my-map "itemOne") {:keyOne   []
                                                        :keyTwo   ["itemTwo" "itemThree"]
                                                        :keyThree ["itemFour" "itemFive" "itemSix"]}))

我对 clojure 还很陌生,对不同的解决方案很感兴趣。 所以欢迎提出任何意见。

解决方法

我会选择这样的:

user> (defn remove-item [my-map item]
        (into {}
              (map (fn [[k v]] [k (remove #{item} v)]))
              my-map))
#'user/remove-item

user> (remove-item my-map "itemFour")

;;=> {:keyOne ("itemOne"),;;    :keyTwo ("itemTwo" "itemThree"),;;    :keyThree ("itemFive" "itemSix")}

您还可以编写一个方便的函数 map-val 对地图值执行映射:

(defn map-val [f data]
  (reduce-kv
   (fn [acc k v] (assoc acc k (f v)))
   {} data))

或者像这样:

(defn map-val [f data]
  (reduce #(update % %2 f) data (keys data)))

user> (map-val inc {:a 1 :b 2})
;;=> {:a 2,:b 3}

(defn remove-item [my-map item]
  (map-val (partial remove #{item}) my-map))

user> (remove-item my-map "itemFour")
;;=> {:keyOne ("itemOne"),;;    :keyThree ("itemFive" "itemSix")}
,

我投入了 specter 版本很好。它将向量保留在地图内 而且它真的很紧凑。

(setval [MAP-VALS ALL #{"itemFive"}] NONE my-map)

示例

user=> (use 'com.rpl.specter)
nil
user=> (def my-map {:keyOne   ["itemOne"]
  #_=>              :keyTwo   ["itemTwo" "itemThree"]
  #_=>              :keyThree ["itemFour" "itemFive" "itemSix"]})
  #_=> 
#'user/my-map
user=> (setval [MAP-VALS ALL #{"itemFive"}] NONE my-map)
{:keyOne ["itemOne"],:keyThree ["itemFour" "itemSix"],:keyTwo ["itemTwo" "itemThree"]}
user=> (setval [MAP-VALS ALL #{"unknown"}] NONE my-map)
{:keyOne ["itemOne"],:keyThree ["itemFour" "itemFive" "itemSix"],:keyTwo ["itemTwo" "itemThree"]}
,

我认为您的解决方案基本没问题,但我会尽量避免使用 apply merge 部分,因为您可以使用 into 从序列轻松重新创建地图。此外,您还可以使用 map 而不是 for,我认为在这种情况下它更惯用一点,因为您不使用 for 的任何列表理解功能。

(defn remove-item-from-map-value [m item]
    (->> m
         (map (fn [[k vs]]
                {k (remove #(= item %) vs)}))
         (into {})))
,

另一个很像@leetwinski 的解决方案:

(defn remove-item [m i]
  (zipmap (keys m)
          (map (fn [v] (remove #(= % i) v))
               (vals m)))) 
,

这是一个以优雅的方式做到这一点的单线。我在这个场景中使用的完美函数是 clojure.walk/prewalk。这个 fn 的作用是遍历你传递给它的表单的所有子表单,并用提供的 fn 转换它们:

(defn remove-item-from-map-value [data item] 
  (clojure.walk/prewalk #(if (map-entry? %) [(first %) (remove #{item} (second %))] %) data))

remove-item-from-map-value fn 将检查当前表单是否是地图条目,如果是,它将从其值中删除指定的键(地图条目的第二个元素,它是一个包含分别是键和值)。

这种方法的最佳之处在于它是完全可扩展的:您可以决定为不同类型的表单做不同的事情,您还可以处理嵌套表单等。

我花了一些时间来掌握这个 fn,但一旦我掌握了它,我发现它非常有用!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?