Clojure 中的外部联接

Posted

技术标签:

【中文标题】Clojure 中的外部联接【英文标题】:Outer join in Clojure 【发布时间】:2012-10-12 04:11:37 【问题描述】:

类似这个问题:Inner-join in clojure

是否有针对任何 Clojure 库中的地图集合执行外连接(左、右和全)的功能?

我想这可以通过修改clojure.set/join的代码来完成,但这似乎是一个足够普遍的要求,所以值得检查它是否已经存在。

类似这样的:

(def s1 #:a 1, :b 2, :c 3
          :a 2, :b 2)

(def s2 #:a 2, :b 3, :c 5
          :a 3, :b 8)


;=> (full-join s1 s2 :a :a)
;
;   #:a 1, :b 2, :c 3
;     :a 2, :b 3, :c 5
;     :a 3, :b 8

以及左右外连接的相应函数,即包括左侧、右侧或两侧的连接键没有值(或nil值)的条目。

【问题讨论】:

【参考方案1】:

Sean Devlin(Full Disclojure 成名)table-utils 具有以下联接类型:

内连接 左外连接 右外连接 完全外连接 自然连接 交叉连接

它已经有一段时间没有更新了,但可以在 1.3、1.4 和 1.5 中使用。让它在没有任何外部依赖的情况下工作:

fn-tuple 替换为juxt 将 ns 声明中的整个 (:use ) 子句替换为 (require [clojure.set :refer [intersection union]]) 从下面添加函数 map-vals:

要么

(defn map-vals
  [f coll]
  (into  (map (fn [[k v]] k (f v)) coll)))

或者对于 Clojure 1.5 及更高版本

(defn map-vals
  [f coll]
  (reduce-kv (fn [acc k v] (assoc acc k (f v)))  coll))

库的使用是join类型,两个集合(如上例的两组map,或者两个sql结果集)和至少一个join fn。由于关键字是地图上的函数,通常只有连接键就足够了:

=> (full-outer-join s1 s2 :a :a)
   (:a 1, :c 3, :b 2
    :a 2, :c 5, :b 3
    :b 8, :a 3)

如果我没记错的话,Sean 前段时间曾尝试将 table-utils 加入 contrib,但从未成功。太糟糕了,它从来没有拥有自己的项目(在 github/clojars 上)。 *** 或 Clojure Google 小组中时不时会出现有关此类库的问题。

另一个选项可能是使用来自 datomic 的数据日志库来查询 clojure 数据结构。 Stuart Halloway 在他的要点中有some examples。

【讨论】:

虽然我最初不愿意复制和粘贴代码,但这是我最终解决问题的方法。谢谢! 我也有同样的犹豫,但是有 SQL 背景,这些抽象自然而然,所以最后我屈服了。也许我会尝试自己写一个这样的库并推动它到 Clojars,但我对 github 和开源的东西不是很熟悉.. 我尝试使用 Clojure 1.6,在上述建议的修复之后,它适用于上面的示例,但是我有 2 个表的堆栈溢出错误,每个表大约有 4,000 行。这是错误:“java.lang.***Error:null”。我已经用 :jvm-opts ["-Xmx1024m"] 设置了我的项目,请提出任何简单的修复或替代方案。谢谢! 源码中join-worker的实现中将“reduce concat”替换为“apply concat”可以解决栈溢出问题。

以上是关于Clojure 中的外部联接的主要内容,如果未能解决你的问题,请参考以下文章

Clojure基础课程2-Clojure中的数据长啥样?

-> Clojure 中的运算符

clojure 中的分析(用于大型代码)

Clojure 中的惯用错误处理

JRuby中的Clojure STM

Clojure在Android开发中的应用情况