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 如何根据给定的条件对嵌套集合进行分组?_Clojure - Fatal编程技术网

Clojure 如何根据给定的条件对嵌套集合进行分组?

Clojure 如何根据给定的条件对嵌套集合进行分组?,clojure,Clojure,如何根据动态给定的列值对嵌套集合进行分组?例如,假设我们有以下嵌套集合;如何根据第一列和第二列中的值对其进行分组 [[“A”2011“Dan”] [“A”2011“Jon”] [“A”2010“Tim”] [“B”2009“汤姆”] 所需的结果图是: { A { 2011 [['A', 2011, 'Dan'] ['A', 2011, 'Joe']] 2010 [['A', 2010, 'Tim']] } B { 2009 [['B', 2009, 'To

如何根据动态给定的列值对嵌套集合进行分组?例如,假设我们有以下嵌套集合;如何根据第一列和第二列中的值对其进行分组

[[“A”2011“Dan”]
[“A”2011“Jon”]
[“A”2010“Tim”]
[“B”2009“汤姆”]

所需的结果图是:

{ A { 
      2011 [['A', 2011, 'Dan'] ['A', 2011, 'Joe']]
      2010 [['A', 2010, 'Tim']] 
    }
  B { 2009 [['B', 2009, 'Tom']] } 
}
以下是我的解决方案,它几乎可以工作:

(defn nest [data criteria]
  (if (empty? criteria)
    data
    (for [[k v] (group-by #(nth % (-> criteria vals first)) data)]
      (hash-map k (nest v (rest criteria))))))

这让你非常接近

(defn my-group [coll]                                                                                                                                                                                                                       
  (let [m (group-by                                                                                                                                                                                                                         
           #(-> % val first first)                                                                                                                                                                                                          
           (group-by #(second %) coll))]                                                                                                                                                                                                    
    (into {} (for [[k v] m] [k (#(into {} %) v)]))))                                                                                                                                                                                        

(my-group [["A" 2011 "Dan"] ["A" 2011 "Jon"] ["A" 2010 "Tim"] ["B" 2009 "Tom"]])                                                                                                                                                            

{"A" {                                                                                                                                                                                                                                      
      2011 [["A" 2011 "Dan"] ["A" 2011 "Jon"]],                                                                                                                                                                                             
      2010 [["A" 2010 "Tim"]]                                                                                                                                                                                                               
      },                                                                                                                                                                                                                                    
 "B" {2009 [["B" 2009 "Tom"]]}                                                                                                                                                                                                              
}

与Clojure一样,您可能会发现一些不那么冗长的内容

我想到了以下几点:

user=> (def a [["A" 2011 "Dan"] 
               ["A" 2011 "Jon"] 
               ["A" 2010 "Tim"] 
               ["B" 2009 "Tom"] ])

user=> (into {} (for [[k v] (group-by first a)] 
                  [k (group-by second v)]))

{"A" {2011 [["A" 2011 "Dan"] 
            ["A" 2011 "Jon"]], 
      2010 [["A" 2010 "Tim"]]}, 
 "B" {2009 [["B" 2009 "Tom"]]}}

这是我想出的解决办法。它是有效的,但我相信它可以改进

(defn nest [data criteria]
  (if (empty? criteria)
    data
    (into {} (for [[k v] (group-by #(nth % (-> criteria vals first)) data)]
      (hash-map k (nest v (rest criteria)))))))
根据 我需要一个能产生多于2个嵌套的地图的概括。我希望能够为这样的函数提供一个任意函数的列表,这些函数可以通过
groupby
递归运行。以下是我的想法:

(defn map-function-on-map-vals
  "Take a map and apply a function on its values. From [1].
   [1] http://stackoverflow.com/a/1677069/500207"
  [m f]
  (zipmap (keys m) (map f (vals m))))

(defn nested-group-by
  "Like group-by but instead of a single function, this is given a list or vec
   of functions to apply recursively via group-by. An optional `final` argument
   (defaults to identity) may be given to run on the vector result of the final
   group-by."
  [fs coll & [final-fn]]
  (if (empty? fs)
    ((or final-fn identity) coll)
    (map-function-on-map-vals (group-by (first fs) coll)
                              #(nested-group-by (rest fs) % final-fn))))
你的榜样 应用于您的数据集:

cljs.user=> (def foo [ ["A" 2011 "Dan"]
       #_=>            ["A" 2011 "Jon"]
       #_=>            ["A" 2010 "Tim"]
       #_=>            ["B" 2009 "Tom"] ])
cljs.user=> (require '[cljs.pprint :refer [pprint]])
nil
cljs.user=> (pprint (nested-group-by [first second] foo))
{"A"
 {2011 [["A" 2011 "Dan"] ["A" 2011 "Jon"]], 2010 [["A" 2010 "Tim"]]},
 "B" {2009 [["B" 2009 "Tom"]]}}
精确地产生所需的输出
nestedgroupby
可以使用三个、四个或更多的函数,并生成如此多的哈希映射嵌套。也许这会对其他人有所帮助

便利功能
nestedgroupby
还有一个方便的额外功能:
final fn
,默认为
identity
,因此如果不提供,最深的嵌套将返回一个值向量,但如果提供了一个
final fn
,则在最里面的向量上运行。举例说明:如果您只是想知道每个类别和年份中出现了多少行原始数据集:

cljs.user=> (nested-group-by [first second] foo count)
                                               #^^^^^ this is final-fn
{"A" {2011 2, 2010 1}, "B" {2009 1}}
警告
此函数不使用
recur
,因此深度递归调用可能会破坏堆栈。然而,对于预期的用例,只有少量的函数,这应该不会是一个问题。

我认为最惯用的版本是:

(defn nest-by
  [ks coll]
  (let [keyfn (apply juxt ks)]
    (reduce (fn [m x] (update-in m (keyfn x) (fnil conj []) x)) {} coll)))
这充分利用了这样一个事实,即中的
更新已经完成了您想要的大部分工作。在您的特殊情况下,您只需:

(nest-by [first second] [["A" 2011 "Dan"]
                         ["A" 2011 "Jon"]
                         ["A" 2010 "Tim"]
                         ["B" 2009 "Tom"] ])

{"A" {2011 [["A" 2011 "Dan"] ["A" 2011 "Jon"]], 2010 [["A" 2010 "Tim"]]}, "B" {2009 [["B" 2009 "Tom"]]}}

当动态提供标准时,我们可以做什么?例如,如果在运行时向we提供了一个映射,即
{:date 1:name 2}
——这表示我们希望根据日期和名称进行分组,日期和名称是每个嵌套集合中的第2列和第3列?我已经尝试递归地构建嵌套集合,但我还没有完全弄明白。将
第一个
更改为
#(n%(:name amap))
,将
第二个
更改为
#(n%(:date amap))
我认为使用索引向量作为标准而不是映射更简单、更正确,看到我们从未使用过钥匙,而且VAL也不能保证正常工作:)