如何从Clojure中的嵌套映射生成列表?

如何从Clojure中的嵌套映射生成列表?,clojure,maps,Clojure,Maps,我有一个原子: (def test (atom {:james {:friends [:lucy :john :daisy]}, :lucy {:friends [:james :daisy]}, :daisy {:friends [:james :lucy]}, :john {:friends [:james]}})) Giving:james作为一个参数,我需要迭代它的:friends,并

我有一个原子:

(def test (atom {:james {:friends [:lucy :john :daisy]},
                 :lucy {:friends [:james :daisy]},
                 :daisy {:friends [:james :lucy]},
                 :john {:friends [:james]}}))
Giving:james作为一个参数,我需要迭代它的:friends,并将:james friends的每个friends放入一个列表中。结果一定是这样的:

(:james :daisy :james :james :lucy)
这是我迄今为止最大的努力:

(def user :james)

(def test2 (atom []))

(defn access
  [user]
  (get-in @test [user :friends]))

(doseq [connection (access user)]
  (swap! test2 concat (access connection)))

@test2

我不认为使用另一个atom test2是最惯用的方法。

没错,您不需要中间的atom

(def users (atom {:james {:friends [:lucy :john :daisy]},
                 :lucy   {:friends [:james :daisy]},
                 :daisy  {:friends [:james :lucy]},
                 :john   {:friends [:james]}}))

(defn friends [dict level users]
    (-> (fn [users] (mapcat #(get-in dict [% :friends]) users))
        (iterate users)
        (nth level)))

(friends @users 2 [:james])

没错,你不需要中间原子

(def users (atom {:james {:friends [:lucy :john :daisy]},
                 :lucy   {:friends [:james :daisy]},
                 :daisy  {:friends [:james :lucy]},
                 :john   {:friends [:james]}}))

(defn friends [dict level users]
    (-> (fn [users] (mapcat #(get-in dict [% :friends]) users))
        (iterate users)
        (nth level)))

(friends @users 2 [:james])

我只会在整个应用程序的最外层使用原子。它们是可共享的、可并发访问的、可变的。。。数据通常是全球性的

写下你需要的函数,让它们尽可能好地与这些事情无关。如果您最终使用纯函数,那么测试就容易多了。如果你想积累数据,那就塑造它;返回前有辅助计算步骤等

这大概就是我要走的路线。注意,有很多方法可以剥猫的皮来浓缩你的列表,我选择了mapcat:

defn用户 [用户名称] 获取用户的用户名 德芬朋友 [用户] 获取用户:好友 defn用户朋友 [用户名称] 一些->>用户名用户朋友 德芬朋友 [用户名称] 当让[好友名称用户好友用户用户名] mapcat部分用户好友用户好友名称;XXX累积混凝土的更换 最后,在您的测试或REPL中:

让[用户{:詹姆斯{:朋友[:露西:约翰:黛西]} :露西{:朋友[:詹姆斯:黛西]} :黛西{:朋友[:詹姆斯:露西]} :约翰{:朋友[:詹姆斯]}] 好友用户:詹姆斯 ; => :詹姆斯:黛西:詹姆斯:詹姆斯:露西
我只会在整个应用程序的最外层使用原子。它们是可共享的、可并发访问的、可变的。。。数据通常是全球性的

写下你需要的函数,让它们尽可能好地与这些事情无关。如果您最终使用纯函数,那么测试就容易多了。如果你想积累数据,那就塑造它;返回前有辅助计算步骤等

这大概就是我要走的路线。注意,有很多方法可以剥猫的皮来浓缩你的列表,我选择了mapcat:

defn用户 [用户名称] 获取用户的用户名 德芬朋友 [用户] 获取用户:好友 defn用户朋友 [用户名称] 一些->>用户名用户朋友 德芬朋友 [用户名称] 当让[好友名称用户好友用户用户名] mapcat部分用户好友用户好友名称;XXX累积混凝土的更换 最后,在您的测试或REPL中:

让[用户{:詹姆斯{:朋友[:露西:约翰:黛西]} :露西{:朋友[:詹姆斯:黛西]} :黛西{:朋友[:詹姆斯:露西]} :约翰{:朋友[:詹姆斯]}] 好友用户:詹姆斯 ; => :詹姆斯:黛西:詹姆斯:詹姆斯:露西
进行此类查询的另一种方法或称之为“间接”方法是通过,首先将嵌套映射转换为事实:

def友谊地图猫fn[[p{xs:friends}] 对于[f xs] [p:个人/朋友f] {:james{:friends[:lucy:john:daisy]}, :露西{:朋友[:詹姆斯:黛西]}, :黛西{:friends[:james:lucy]}, :约翰{:朋友[:詹姆斯]} ;; => [:詹姆斯:人/朋友:露西] [:詹姆斯:人/朋友:约翰] [:詹姆斯:人/朋友:黛西] [:露西:人/朋友:詹姆斯] [:露西:人/朋友:黛西] [:黛西:人/朋友:詹姆斯] [:黛西:人/朋友:露西] [:约翰:人/朋友:詹姆斯] 然后使用自定义规则(如friend和friend of friend)对事实执行数据日志查询。例如,寻找朋友的朋友:詹姆斯:

d/q'[:查找[?f…] :朋友的朋友在哪里 :单位:美元?p%] 友谊 :詹姆斯 “[[friend?p?f [?p:个人/朋友?f]] [朋友的朋友?p?f 朋友?p?x 朋友?x?f [not=?p?f]] ;; => [:黛西:露西] 在哪里

[:查找[?f…] :朋友的朋友在哪里 :单位:美元?p%] 是查询,友谊是事实并映射到$,:james是映射到参数的查询主题?p和%是定义为以下内容的规则:

什么是朋友? [?p:person/friend?f]];?p有一个属性:person/friend用?f定义 [朋友的朋友?p?f;2.朋友的朋友 朋友?p?x;?p和?x是基于1的朋友 朋友?x?f;?x和?f是朋友 [not=?p?f]]?p和?f不是同一个人
注意:上面的示例使用的是另一种方式,或者您称之为“间接”方式来执行此类查询,即首先将嵌套映射转换为事实:

def友谊地图猫fn[[p{xs:friends}] 对于[f xs] [p:个人/朋友f] {:james{:friends[:lucy:john:daisy]}, :露西{:朋友[:詹姆斯:黛西]}, :黛西{:friends[:james:lucy]}, :约翰{:朋友[:詹姆斯]} ;; => [:詹姆斯:人/朋友:露西] [:詹姆斯:人/朋友:约翰] [:詹姆斯:人/朋友:黛西] [:露西:人/朋友:詹姆斯] [:露西:人/朋友:黛西] [:黛西:人/朋友:詹姆斯] [:黛西:人/朋友:露西] [:约翰:人/朋友:詹姆斯] 然后使用自定义规则(如friend和friend of friend)对事实执行数据日志查询。例如,寻找朋友的朋友:詹姆斯:

d/q'[:查找[?f…] :朋友的朋友在哪里 :单位:美元?p%] 友谊 :詹姆斯 “[[friend?p?f [?p:个人/朋友?f]] [朋友的朋友?p?f 朋友?p?x 朋友?x?f [not=?p?f]] ;; => [:黛西:露西] 在哪里

[:查找[?f…] :朋友的朋友在哪里 :单位:美元?p%] 是查询,友谊是事实并映射到$,:james是映射到参数的查询主题?p和%是定义为以下内容的规则:

什么是朋友? [?p:person/friend?f]];?p有一个属性:person/friend用?f定义 [朋友的朋友?p?f;2.朋友的朋友 朋友?p?x;?p和?x是基于1的朋友 朋友?x?f;?x和?f是朋友 [not=?p?f]]?p和?f不是同一个人
注意:上面的示例使用的是

,这里有一种方法可以解决使用core.logic和facts的可传递好友问题。首先,为友谊做一个事实DB和DB rel:

(require '[clojure.core.logic :refer :all]
         '[clojure.core.logic.pldb :as pldb])

(def input
  {:james {:friends [:lucy :john :daisy]},
   :lucy  {:friends [:james :daisy]},
   :daisy {:friends [:james :lucy]},
   :john  {:friends [:james]}})

(pldb/db-rel friend p1 p2)

(def friends
  (apply pldb/db
    (for [[p1 {:keys [friends]}] input
          p2 friends]
      [friend p1 p2])))
然后编写一个函数,将一个朋友的答案绑定到该朋友的所有朋友的朋友


下面是一个用core.logic和facts解决可传递朋友问题的方法。首先,为友谊做一个事实DB和DB rel:

(require '[clojure.core.logic :refer :all]
         '[clojure.core.logic.pldb :as pldb])

(def input
  {:james {:friends [:lucy :john :daisy]},
   :lucy  {:friends [:james :daisy]},
   :daisy {:friends [:james :lucy]},
   :john  {:friends [:james]}})

(pldb/db-rel friend p1 p2)

(def friends
  (apply pldb/db
    (for [[p1 {:keys [friends]}] input
          p2 friends]
      [friend p1 p2])))
然后编写一个函数,将一个朋友的答案绑定到该朋友的所有朋友的朋友


非常感谢你!如果我想数一数这些朋友并进行分类,把这个列表变成这样:{:詹姆斯3,:黛西1,:露西1},你知道我该怎么做吗?非常感谢!如果我想数一数这些朋友并进行分类,把这个列表变成这样:{:詹姆斯3,:黛西1,:露西1},你知道我该怎么做吗?非常感谢!如果我想数一数朋友并进行排序,把列表变成这样:{:詹姆斯3,:黛西1,:露西1},你知道我该怎么做吗?频率朋友用户:詹姆斯->{:黛西1,:詹姆斯3,:露西1}哦,很简单!我怎样才能按val分类呢?我找到了这个,但是还有更好的方法吗?非常感谢!如果我想数一数朋友并进行排序,把列表变成这样:{:詹姆斯3,:黛西1,:露西1},你知道我该怎么做吗?频率朋友用户:詹姆斯->{:黛西1,:詹姆斯3,:露西1}哦,很简单!我怎样才能按val分类呢?我找到了这个,但是还有更好的方法吗?