Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
当值包含复合数据时,在Clojure中按值筛选hashmap_Clojure_Hashmap - Fatal编程技术网

当值包含复合数据时,在Clojure中按值筛选hashmap

当值包含复合数据时,在Clojure中按值筛选hashmap,clojure,hashmap,Clojure,Hashmap,我在努力自学Clojure 对于一个与工作相关的项目(很明显,我不是一个专业的程序员),我尝试将一系列电子表格结合起来。电子表格中有与金融交易相关的注释。多个注释(包括电子表格中的注释)可以引用同一交易;每个事务都有一个唯一的序列号。因此,我使用以下数据结构来表示电子表格: (def ss { :123 '([ "comment 1" "comment 2" ] [ "comment 3" "comment 4" ] [ "co

我在努力自学Clojure

对于一个与工作相关的项目(很明显,我不是一个专业的程序员),我尝试将一系列电子表格结合起来。电子表格中有与金融交易相关的注释。多个注释(包括电子表格中的注释)可以引用同一交易;每个事务都有一个唯一的序列号。因此,我使用以下数据结构来表示电子表格:

(def ss { :123 '([ "comment 1" "comment 2" ]
                 [ "comment 3" "comment 4" ]
                 [ "comment 5" ]),
          :456 '([ "happy days" "are here" ]
                 [ "again" ])})
这可以通过以下两个电子表格创建:

+------------+------------+-----------+
| Trans. No. |   Cmt. A   |  Cmt. B   |
+------------+------------+-----------+
|        123 | comment 1  | comment 2 |
|        456 | happy days | are here  |
|        123 | comment 3  | comment 4 |
+------------+------------+-----------+

+-----------------+------------+
| Analyst Comment | Trans. No. |
+-----------------+------------+
| comment 5       |        123 |
| again           |        456 |
+-----------------+------------+
我已经成功地编写了函数来创建这个数据结构,给出了一个充满CSV的目录。我想再写两个函数:

;; FUNCTION 1 ==========================================================
;; Regex Spreadsheet -> Spreadsheet     ; "Spreadsheet" is like ss above 
;; Produces a Spreadsheet with ALL comments per transaction if ANY
;;     value matches the regex

; (defn filter-all [regex my-ss]     {}) ; stub

(defn filter-all [regex my-ss]           ; template
  (... my-ss))

(deftest filter-all-tests
  (is (= (filter-all #"1" ss) 
         { :123 '([ "comment 1" "comment 2" ]
                  [ "comment 3" "comment 4" ]
                  [ "comment 5" ]) })))

;; FUNCTION 2 ==========================================================
;; Regex Spreadsheet -> Spreadsheet     ; "Spreadsheet" is like ss above 
;; Produces a Spreadsheet with each transaction number that has at least
;;     one comment that matches the regex, but ONLY those comments that 
;;     match the regex

; (defn filter-matches [regex my-ss] {}) ; stub

(defn filter-matches [regex my-ss]       ; template
  (... my-ss))

(deftest filter-matches-tests
  (is (= (filter-matches #"1" ss) 
         { :123 '([ "comment 1" ]) })))
我不明白的是,对于每个
,如果它们是嵌套在列表中的向量中的字符串,那么最好的方法是将正则表达式足够深入地放入
VAL
。我曾尝试将
filter
与嵌套的
apply
s或
map
s一起使用,但我对语法感到困惑,即使它起作用,我也不知道如何使用
键来构建新的hashmap

我也尝试过在
filter
函数中使用解构,但我也感到困惑,我还认为我必须跨嵌套数据“提升”函数(我认为这是Haskell中的术语,如应用程序和monad)

有人能建议过滤此数据结构的最佳方法吗?作为另一件事,我很乐意就这是否是一个适合我的合理数据结构获得反馈,但我希望了解如何解决目前存在的问题,如果只是为了学习的目的


非常感谢。

这里有一个与您的数据结构相关的解决方案。
filter
采用谓词函数。在这个函数中,您实际上可以在数据结构中测试您需要的任何东西。在这里,
flatten
有助于删除注释向量列表

(defn filter-all [regex my-ss]
  (into {} (filter (fn [[k v]] ; map entry can be destructured into a vector
                     ; flatten the vectors into one sequence
                     ; some return true if there is a match on the comments 
                     (some #(re-matches regex %) (flatten v)))
                   my-ss)))

user> (filter-all #".*3.*" ss)
{:123 (["comment 1" "comment 2"] ["comment 3" "comment 4"] ["comment 5"])}
对于
过滤器匹配
来说,逻辑是不同的:您希望使用值的某些部分构建一个新映射<代码>减少
有助于做到这一点:

(defn filter-matches [regex my-ss]
  (reduce (fn [m [k v]]   ; m is the result map (accumulator)
            (let [matches (filter #(re-matches regex %) (flatten v))]
              (when (seq matches)
                (assoc m k (vec matches)))))
          {}
          my-ss))

user> (filter-matches #".*days.*" ss)
{:456 ["happy days"]}

对于数据结构本身,如果没有必要将嵌套向量保留在每个条目的列表中,您可以使用
{:123[“comment1”“comments 2”]…}
进行简化,但这不会大大简化上述函数。

我认为您的方法是正确的,但可能会使生活变得比需要的困难一些

最大的问题是正则表达式的使用。虽然regexp在某些方面是一个很好的工具,但在其他解决方案更好、速度更快的时候,经常使用它

clojure采用的一个关键思想是使用小型库,将它们组装在一起以获得更高级别的抽象。例如,有各种库用于处理不同的电子表格格式,如excel、google docs电子表格,并且支持处理CSV文件。因此,我的第一步是看看您是否能找到一个库,将您的spreadhseet解析为标准的clojure数据结构

例如,clojure的data.csv将csv电子表格处理成一个向量的惰性序列,其中每个向量是电子表格中的一行,向量中的每个元素是该行中的一列值。一旦你有了这种格式的数据,然后用map、filter等处理它就相当简单了

下一步是考虑将使处理尽可能简单的抽象类型。这在很大程度上取决于您计划做什么,但我对这类数据的建议是使用一个嵌套结构,该结构由哈希映射组成,在外层由您的事务号索引,然后每个值都是一个哈希映射,该哈希映射在电子表格中的每一列都有一个条目

{:123 {:cmnta ["comment 1" "comment 3"]
      :cmntb ["comment 2" "comment 4"]
      :analstcmt ["comment 5"]}
 :456 {:cmnta ["happy days"]
      :cmntb ["are here"]
      :analystcmt ["again"]}}
有了这个结构,您就可以使用诸如get in和update in之类的函数来访问/更改结构中的值,即

(get-in m [123 :cmnta]) => ["comment 1" "comment 3"]
(get-in m [123 :cmnta 0]) => "comment 1"
(get-in m [456 :cmnta 1]) => nil
(get-in m [456 :cmnta 1] "nothing to see here - move on") => "nothing to see here - move on"

我假设不同的评论向量来自不同的CSV文件?是否要求将它们分开?如果不存储它们来自何处的信息,这似乎是一个不必要的复杂问题。它们是同一行上的不同细胞。我可能可以去掉它们,但我也希望有一个选项,可以用匹配的单元格显示整行,或者只显示匹配的单元格。谢谢,这是一个有用的补充。我使用data.csv获得了我上面描述的数据结构,但可能我对它的切割程度超出了需要,并且削弱了使用抽象的能力。也就是说,就我而言,正则表达式可能是有用的(我是一名律师,我们正在使用各种搜索词来查看交易的评论是否值得一个人查看)。正则表达式可能有用,但要小心。锚定正则表达式以确保性能不会受到很大影响,这一点非常重要。尽管您可能不想走得更远,但通过查看clojure中正在进行的一些自然语言处理(NLP)工作,您可能会做得更好。