如何在clojure中迭代ArrayMap?

 东明街道老年日托 发布于 2023-02-10 12:01

我对clojure(昨天开始学习)和函数式编程完全不熟悉所以请原谅我的无知.我一直在尝试阅读很多clojure文档,但其中很多都完全超出了我的想法.

我正在尝试迭代这个设置的ArrayMap:

{city1 ([[0 0] [0 1] [1 1] [1 0]]), city2 ([[3 3] [3 4] [4 4] [4 3]]), city3 ([[10 10] [10 11] [11 11] [11 10]])} 

(^希望语法是正确的,这就是我的终端正在打印的样子)

其中城市名称映射到矢量矢量,矢量定义构成该城市边界的点.我需要将所有这些点与外部点进行比较,以确定外部点是否在这些城市之一,如果是,那么它在哪个城市.

我正在使用此处详述的射线投射算法来确定外部点是否在矢量矢量内.

1 个回答
  • Maps实际上实现了clojure.lang.ISeq接口,这意味着您可以对它们使用所有更高级别的序列操作.单个元素是表单的对[key value],因此,要找到匹配谓词的第一个元素,in-city?您可以使用some:

    (some
      (fn [[city-name city-points]]                  ;; the current entry of the map
        (when (in-city? the-other-point city-points) ;; check the borders
          city-name))                                ;; return the name of a matching city
      cities)
    

    您也可以使用keep查找与谓词匹配的所有元素,但我猜您的示例中的城市之间没有重叠.


    更新:让我们退一步,因为使用序列很有趣.我不打算深入研究所有序列类型,只使用vectors([1 2 3 ...])作为例子.

    好的,首先,让我们访问我们的向量:

    (first [1 2 3]) ;; => 1
    (rest [1 2 3])  ;; => [2 3]
    (last [1 2 3])  ;; => 3
    (nth [1 2 3] 1) ;; => 2
    

    功能编程的好处是,函数只是可以传递给其他函数的值.例如,您可能希望将一个函数(假设为"将数字加2")应用于序列中的每个元素.这可以通过map以下方式完成:

    (map
      (fn [x]
        (+ x 2))
      [1 2 3])
    ;; => [3 4 5]
    

    如果你还没有看到它,那么函数值有一个简写,%第一个参数%2是第二个参数,依此类推:

    (map #(+ % 2) [1 2 3]) ;; => [3 4 5]
    

    这简洁实用,您可能会在野外看到很多.当然,如果您的函数有名称或存储在var中(例如通过使用defn),您可以直接使用它:

    (map pos? [-1 0 1]) ;; => [false false true]
    

    像这样使用谓词并没有多大意义,因为你丢失了产生布尔结果的实际值.以下怎么样?

    (filter pos? [-1 0 1]) ;; => [1]
    (remove pos? [-1 0 1]) ;; => [-1 0]
    

    这会选择或丢弃与谓词匹配的值.在这里,您应该能够看到与城市边界示例的连接:您希望在地图中找到包含给定点的所有城市p.但地图不是序列,是吗?确实他们是:

    (seq {:a 0 :b 1}) ;; => [[:a 0] [:b 1]]
    

    哦,我的,可能性!

    (map first {:a 0 :b 1})                 ;; => [:a :b]
    (filter #(pos? (second %)) {:a 0 :b 1}) ;; => [[:b 1]]
    

    filter 检索所有匹配的城市(及其坐标)但由于您只对名称感兴趣 - 这些名称存储为每对的第一个元素 - 您必须从每个元素中提取它,类似于以下(更简单)的示例:

    (map first (filter #(pos? (second %)) {:a 0 :b 1})) 
    :: => [:b]
    

    实际上有一个结合map和的功能filter.它被调用keep并返回nil其谓词产生的每个非值.因此,您可以检查每对中的第一个元素,然后返回第二个元素:

    (keep
      (fn [pair]
        (when (pos? (second pair))
          (first pair)))
      {:a 0 b 1})
    ;; => [:b]
    

    每次你看到自己使用了很多firsts和seconds,也许只有几个rests,你应该想到解构.它可以帮助您以简单的方式访问部分值,我不会在这里详细介绍,但它可以非常直观地用于序列:

    (keep
      (fn [[a b]] ;; instead of the name 'pair' we give the value's shape!
        (when (pos? b)
          a))
      {:a 0 :b 1})
    ;; => [:b]
    

    如果您只对第一个结果感兴趣,当然可以直接访问它并编写类似的内容(first (keep ...)).但是,由于这是一个非常常见的用例,someClojure 会为您提供.这就像keep但不会超越第一场比赛.让我们深入了解您的城市示例,其解决方案现在应该开始有意义:

    (some
      (fn [[city-name city-points]]
        (when (in-city? p city-points)
          city-name))
      all-cities)
    

    所以,我希望这对你有用.

    2023-02-10 12:06 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有