Dictionary Clojure:map函数不是';I don’我不能返回我能评估的东西

Dictionary Clojure:map函数不是';I don’我不能返回我能评估的东西,dictionary,clojure,Dictionary,Clojure,我正在写一个小的“秘密圣诞老人”程序,用Clojure把我的手弄脏,我的输出结果却步履蹒跚 该程序获取一个集合列表(圣诞老人),将他们的电子邮件提取到另一个列表中,然后将收件人随机分配给圣诞老人。我想我基本上已经知道了,但是当我试图输出我的地图的结果时,我得到了 您的assign santas功能返回一个map传感器。当您将map应用于单个参数时,它将返回一个转换器,该转换器将在转换上下文中执行该转换。很可能您打算提供第三个参数,santas,以进行映射 在assign santas函数中,您正

我正在写一个小的“秘密圣诞老人”程序,用Clojure把我的手弄脏,我的输出结果却步履蹒跚

该程序获取一个集合列表(圣诞老人),将他们的电子邮件提取到另一个列表中,然后将收件人随机分配给圣诞老人。我想我基本上已经知道了,但是当我试图输出我的
地图的结果时,我得到了


您的
assign santas
功能返回一个map传感器。当您将
map
应用于单个参数时,它将返回一个转换器,该转换器将在转换上下文中执行该转换。很可能您打算提供第三个参数,
santas
,以进行映射


assign santas
函数中,您正在使用
@
对非原子的值进行排序。也许你的意思是
@r
而不是
@recipients
,但是你的let块停止得太快了,还没有向函数体的其余部分提供
r
绑定。

也要注意如何使用
map
。您正在返回
交换的结果
继续努力使您的版本正确编译和运行。我想为您的问题提供一个替代解决方案,该解决方案不太适用于突变,而是专注于组合集合

(德夫兰·桑塔斯)
“随机化当前圣诞老人列表”
(洗牌圣诞老人)
(2)圣诞老人
“使用重叠分区将所有随机圣诞老人配对”
(第2分区1兰德·桑塔斯)
(def最终配对)
“将列表中的第一个作为圣诞老人添加到最后一个,以确保每个人都是成对的”
(联合成对的圣诞老人(名单(最后一个兰特圣诞老人)(第一个兰特圣诞老人)))
(圣诞老人)
“遍历所有对,并将第二对关联到第一对,作为秘密圣诞老人”
[配对]
(地图
(fn[[受欢迎的圣诞老人]]
(助理收件人:圣塔人)
配对)
(defn-main[]
(pprint/pprint(注入圣诞老人最后一对)))
Lisp(一般)和Clojure(特定情况)是不同的,需要不同的方法来处理问题。学习如何使用Clojure解决问题的一部分似乎是忘记了我们在执行命令式编程时养成的许多习惯。特别是,在使用命令式语言执行某些操作时,我们经常会想,“如何从空集合开始,然后在遍历数据时向其中添加元素,从而得到所需的结果?”。这不是个好主意,克洛尤尔·怀斯。在Clojure中,思考过程需要更为大致,“我有一个或多个包含我的数据的集合。我如何将函数应用于这些集合,很可能在过程中创建中间(可能是丢弃)集合,以最终获得我想要的结果集合?”

好吧,让我们切入正题,然后回头看看我们为什么要这么做。下面是我如何修改原始代码的:

(def santas [{:name "Foo" :email "foo@gmail.com"}
             {:name "Bar" :email "bar@gmail.com"}
             {:name "Baz" :email "baz@gmail.com"}])

(def kids [{:name "Tommy" :email "tommy@gmail.com"}
           {:name "Jimmy" :email "jimmy@gmail.com"}
           {:name "Jerry" :email "jerry@gmail.com"}
           {:name "Johny" :email "johny@gmail.com"}
           {:name "Juney" :email "juney@gmail.com"}])

(defn pluck
  "Pull out the value of a given key from a seq"
  [arr k]
  (map #(get % k) arr))

(defn assign-santas [recipients santas]
  ; Assign kids to santas randomly
  ; recipients is a shuffled/randomized vector of kids
  ; santas is a vector of santas

  (let [santa-reps  (inc (int (/ (count recipients) (count santas))))  ; counts how many repetitions of the santas collection we need to cover the kids
        many-santas (flatten (repeat santa-reps santas))]              ; repeats the santas collection 'santa-reps' times
    (map #(hash-map :santa %1 :kid %2) many-santas recipients)
  )
)

(defn assign-santas-main []
  (let [recipients (shuffle (pluck kids :email))
        pairs (assign-santas recipients (map #(%1 :name) santas))]
      ; (pprint/pprint pairs)
      pairs))
我创建了一个单独的孩子集合,他们应该被随机分配给圣诞老人。我还对其进行了更改,使其创建了一个
assignsantasmain
函数,而不是
-main
,仅用于测试目的

唯一更改的功能是分配圣诞老人。我没有从一个空集合开始,然后尝试对该集合进行变异以积累我们需要的关联,而是执行了以下操作:

  • 确定需要重复多少次“圣诞老人”
  • 系列,这样我们就至少有了和孩子一样多的圣诞老人(等等-我们会找到的…:-)。这只是

    TRUNC(#u of_kids/#u of_santas)+1

    或者,用Clojure的话说

    `(inc (int (/ (count recipients) (count santas))))`
    
  • 创建一个集合,
    santas
    集合根据需要重复多次(从步骤1开始)。这件事就这样结束了

    (展平(重复圣诞老人代表圣诞老人))

  • 这将(
    repeat
    )圣诞老人的集合
    圣诞老人的重复次数(
    santa reps
    由步骤1计算)复制(
    santa reps
    ),然后
    展平它-即从所有子集合中获取元素(尝试执行
    (repeat 3 santas)
    ,看看得到什么)然后将所有子集合的元素组成一个大的平面集合

  • 然后我们就这样做了

    (映射(散列映射:圣诞老人%1:kid%2)许多圣诞老人收件人)

  • 这表示“从每个
    多个圣诞老人
    接收者
    集合中获取第一个元素,将它们传递给给定的匿名函数,然后将函数返回的结果累积到新集合中”。(新系列,再次-我们在Clojure做了很多)。我们的小匿名函数说“创建一个关联(
    hash-map
    函数),将
    :santa
    的键分配给第一个参数,将
    :kid
    的键分配给第二个参数”。
    map
    函数然后返回该关联集合

    如果运行
    assign santas main
    函数,则会得到如下结果

    ({:kid "jimmy@gmail.com", :santa "Foo"}
     {:kid "tommy@gmail.com", :santa "Bar"}
     {:kid "jerry@gmail.com", :santa "Baz"}
     {:kid "johny@gmail.com", :santa "Foo"}
     {:kid "juney@gmail.com", :santa "Bar"})
    
    (我把每个协会放在一条单独的线上——Clojure打印出来的时候并没有那么优雅——但你明白了)。如果再次运行,则会得到不同的结果:

    ({:kid "juney@gmail.com", :santa "Foo"}
     {:kid "tommy@gmail.com", :santa "Bar"} 
     {:kid "jimmy@gmail.com", :santa "Baz"}
     {:kid "johny@gmail.com", :santa "Foo"}
     {:kid "jerry@gmail.com", :santa "Bar"})
    
    等等,每一次不同的跑步

    请注意,在重写版的
    assign santas
    中,整个函数可以写在一行上。我在这里只使用了一个
    let
    来打破
    santa reps
    的计算和
    许多圣诞老人的创建,因此很容易看到和解释

    对我来说,我发现使用Clojure很困难的一件事(这是因为我仍然在沿着学习曲线前进——对我来说,有着40多年的命令式编程经验和习惯,这是一个相当陡峭的曲线)就是学习基本函数和如何使用它们。我经常发现一些有用的是
    ({:kid "juney@gmail.com", :santa "Foo"}
     {:kid "tommy@gmail.com", :santa "Bar"} 
     {:kid "jimmy@gmail.com", :santa "Baz"}
     {:kid "johny@gmail.com", :santa "Foo"}
     {:kid "jerry@gmail.com", :santa "Bar"})
    
    map
    apply
    reduce
      I have great difficulty remembering the difference between apply and
      reduce. In practice, if one doesn't do what I want I use the other.
    repeat
    flatten
    interleave
    partition
    hash-map
    mapcat