如何根据唯一值在clojure中从2组中映射不同的值 [英] How to map different values from 2 sets in clojure based on unique value

查看:141
本文介绍了如何根据唯一值在clojure中从2组中映射不同的值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个函数A给出数据

I have a function A which gives the data

{{id 1,:obs/A "11", :obs/value 2.0, :obs/color "yellow"}
{id 2,:obs/A "12", :obs/value 4.0, :obs/color "blue"}
{id 3,:obs/A "13", :obs/value 3.0, :obs/color "green"}
{id 3,:obs/A "15", :obs/value 7.0, :obs/color "red"}...}

and a function B which gives the data

{{id 2,:obs/A "11", :obs/value 7.0, :obs/shape "square"}
{id 2,:obs/A "13", :obs/value 4.0, :obs/shape "circle"}
{id 6,:obs/A "15", :obs/value 3.0, :obs/shape "triangle"}...}

I want to map obs/value from both functions which match with same obs/A.

Here the result will be like {(2.0,7.0),(3.0,4.0)..}

我使用过滤器函数和映射,但是无法获得正确的代码。

I am using filter functions and map but couldnt get correct code.

谢谢。

推荐答案

更新2016-9-26 1727:我添加了一个更好的解决方案,使用DataScript做所有的辛勤工作。

UPDATE 2016-9-26 1727: I added a better solution that uses DataScript to do all of the hard work. Please see the additional solution at the end.

这是一个有效的答案(不含DataScript):

Here is an answer that works (w/o DataScript):

(ns clj.core
  (:require [tupelo.core :as t] 
            [clojure.set :as set] ))
(t/refer-tupelo)

(def x
  [ {:id 1,   :obs/A "11",    :obs/value 2.0,    :obs/color "yellow"}
    {:id 2,   :obs/A "12",    :obs/value 4.0,    :obs/color "blue"}
    {:id 3,   :obs/A "13",    :obs/value 3.0,    :obs/color "green"}
    {:id 3,   :obs/A "15",    :obs/value 7.0,    :obs/color "red"} ] )

(def y
  [ {:id 2,   :obs/A "11",    :obs/value 7.0,    :obs/shape "square"}
    {:id 2,   :obs/A "13",    :obs/value 4.0,    :obs/shape "circle"}
    {:id 6,   :obs/A "15",    :obs/value 3.0,    :obs/shape "triangle"} ] )

(newline) (println "x") (pretty x)
(newline) (println "y") (pretty y)

; Note this assumes that :obs/A is unique in each sequence x and y
(def xa (group-by :obs/A x))
(def ya (group-by :obs/A y))
(newline) (println "xa") (pretty xa)
(newline) (println "ya") (pretty ya)

(def common-a (set/intersection (set (keys xa)) (set (keys ya))))
(newline) (spyx common-a)

(def values-map
  (apply glue
    (for [aval common-a]
      { (-> aval xa only :obs/value)
        (-> aval ya only :obs/value) } )))
(newline) (spyx values-map)


> lein run
x
[{:id 1, :obs/A "11", :obs/value 2.0, :obs/color "yellow"}
 {:id 2, :obs/A "12", :obs/value 4.0, :obs/color "blue"}
 {:id 3, :obs/A "13", :obs/value 3.0, :obs/color "green"}
 {:id 3, :obs/A "15", :obs/value 7.0, :obs/color "red"}]

y
[{:id 2, :obs/A "11", :obs/value 7.0, :obs/shape "square"}
 {:id 2, :obs/A "13", :obs/value 4.0, :obs/shape "circle"}
 {:id 6, :obs/A "15", :obs/value 3.0, :obs/shape "triangle"}]

xa
{"11" [{:id 1, :obs/A "11", :obs/value 2.0, :obs/color "yellow"}],
 "12" [{:id 2, :obs/A "12", :obs/value 4.0, :obs/color "blue"}],
 "13" [{:id 3, :obs/A "13", :obs/value 3.0, :obs/color "green"}],
 "15" [{:id 3, :obs/A "15", :obs/value 7.0, :obs/color "red"}]}

ya
{"11" [{:id 2, :obs/A "11", :obs/value 7.0, :obs/shape "square"}],
 "13" [{:id 2, :obs/A "13", :obs/value 4.0, :obs/shape "circle"}],
 "15" [{:id 6, :obs/A "15", :obs/value 3.0, :obs/shape "triangle"}]}

common-a => #{"15" "13" "11"}

values-map => {7.0 3.0, 3.0 4.0, 2.0 7.0}

就像做一个迷你数据库和询问伪代码):

It is like making a mini database and asking (sql pseudocode):

select x.value, y.value from 
  (natural join x, y on A)

如果你这样做,你可能会发现使用像PostgreSQL或Datomic这样的真实数据库是有用的,

If you are doing this alot, you may find that using a real DB like PostgreSQL or Datomic is useful, or for memory-only stuff consider the clojure lib DataScript.

这里是DataScript答案:

Here is the DataScript answer:

(ns clj.core
  (:require [tupelo.core :as t] 
            [datascript.core :as d]
            [clojure.set :as set] ))
(t/refer-tupelo)

(def data
  [ {:type :x :local/id 1,   :obs/A "11",    :obs/value 2.0,    :obs/color "yellow"}
    {:type :x :local/id 2,   :obs/A "12",    :obs/value 4.0,    :obs/color "blue"}
    {:type :x :local/id 3,   :obs/A "13",    :obs/value 3.0,    :obs/color "green"}
    {:type :x :local/id 3,   :obs/A "15",    :obs/value 7.0,    :obs/color "red"} 

    {:type :y :local/id 2,   :obs/A "11",    :obs/value 7.0,    :obs/shape "square"}
    {:type :y :local/id 2,   :obs/A "13",    :obs/value 4.0,    :obs/shape "circle"}
    {:type :y :local/id 6,   :obs/A "15",    :obs/value 3.0,    :obs/shape "triangle"} ] )

(def conn (d/create-conn {}))
(d/transact! conn data)

(def labelled-result
  (d/q '[:find ?a ?value1 ?value2
             :where 
               [?ex :type :x] [?ex :obs/A ?a] [?ex :obs/value ?value1]
               [?ey :type :y] [?ey :obs/A ?a] [?ey :obs/value ?value2]
            ] @conn ))
(newline) (println "labelled-result") (pretty labelled-result)

(def unlabelled-result
  (d/q '[:find    ?value1 ?value2
             :where 
               [?ex :type :x] [?ex :obs/A ?a] [?ex :obs/value ?value1]
               [?ey :type :y] [?ey :obs/A ?a] [?ey :obs/value ?value2]
            ] @conn ))
(newline) (println "unlabelled-result") (pretty unlabelled-result)

> lein run

labelled-result
#{["13" 3.0 4.0] ["11" 2.0 7.0] ["15" 7.0 3.0]}

unlabelled-result
#{[3.0 4.0] [2.0 7.0] [7.0 3.0]}

这篇关于如何根据唯一值在clojure中从2组中映射不同的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆