Clojure:如何将函数应用于特定嵌套级别的值?
Clojure: How do you apply a function to values at a specific nesting level?
我是 Clojure 的初学者,所以我会尽我所能来表达这一点,
我有一个函数 returns 嵌套列表的列表
在解析了每日温度数据集之后,
每个嵌套列表对应于特定月份的每日临时工,例如 2014 年 2 月、2015 年 2 月等,并使用“-999”作为填充符填充到 31 个项目以保留数据集的结构。
原始数据集:https://www.metoffice.gov.uk/hadobs/hadcet/cetdl1772on.dat
(partition 31 (monthly-helper 2 (parse-into-list "CETdataDailyLong")))
=>((-15 7 15 -25 -5 -45 12 47 56 28 20 40 57 38 2 5 25 -3 0 7 7 -3 -10 -10 30 85 46 77 56 -999 -999)
(0 17 -28 -23 -30 5 -18 -3 -33 -23 -18 -3 -10 50 82 72 62 42 15 57 75 40 92 52 42 62 72 70 -999 -999 -999)
(-2 -12 4 28 12 0 44 27 -12 16 74 61 76 87 77 78 51 51 59 56 64 52 78 63 39 28 33 81 -999 -999 -999)
(97 58 75 103 33 46 88 101 56 47 66 36 52 47 58 42 42 37 63 77 76 43 55 85 58 57 55 66 -999 -999 -999)
(-59 19 28 55 47 30 52 49 42 50 45 25 34 70 40 54 24 13 25 54 85 29 27 38 25 73 44 50 40 -999 -999))
我正在尝试从列表中的所有嵌套列表中删除 -999 值,我需要在对数据进行分区后执行此操作,以避免必须按每个月的天数任意对数据进行分区。
我得到的最接近的是下面但它没有效果,因为它只应用于顶级列表而不是每个嵌套列表中的值,我需要如何修改它以获得我正在寻找的结果,或者问我原来的问题;
如何将函数应用于特定嵌套级别的值?
(remove #(= -999 %)(partition 31 (monthly-helper 2 (parse-into-list "CETdataDailyLong"))))
下面是我的分区函数的大部分结果的最小代码,我认为它非常接近,但如果你能告诉我我遗漏了什么,我将非常感激,谢谢
(remove #(= -999 %)'(((-15 7 15 -25 -5 -45 12 47 56 28 20 40 57 38 2 5 25 -3 0 7 7 -3 -10 -10 30 85 46 77 56 -999 -999)
(0 17 -28 -23 -30 5 -18 -3 -33 -23 -18 -3 -10 50 82 72 62 42 15 57 75 40 92 52 42 62 72 70 -999 -999 -999)
(-2 -12 4 28 12 0 44 27 -12 16 74 61 76 87 77 78 51 51 59 56 64 52 78 63 39 28 33 81 -999 -999 -999)
(97 58 75 103 33 46 88 101 56 47 66 36 52 47 58 42 42 37 63 77 76 43 55 85 58 57 55 66 -999 -999 -999)
(-59 19 28 55 47 30 52 49 42 50 45 25 34 70 40 54 24 13 25 54 85 29 27 38 25 73 44 50 40 -999 -999))))
我已经尝试了下面的方法,并使用地图等对其进行了多种变体,但一无所获,看到一个正确的例子真的会帮助我理解我哪里出错了。
(apply #(remove -999 %) (partition 31 (monthly-helper 2 (parse-into-list "CETdataDailyLong"))))
Exception: Wrong number of args (21) passed
您的第一个展览是一个列表列表。您想要的输出也是一个列表列表——但列表不同。因此,您需要 map
而不是 apply
。
所以 iiuc, the:
- 总表包含年份表,
- 年份列表包含月份列表,
- 月份列表包含当天的温度,
- 每个月份列表都用 -999 填充以使其大小统一:31 个条目长
我看到你已经尝试过:
- 您已使用带谓词的
remove
函数在值等于 -999 时删除。本例中的值是 '((-15 7 15 -25 -5 -45 12 ...))
,它不等于 -999,所以你最终得到的是你开始时的值。
apply
采用函数和 单个参数序列 。您将 21 个列表传递给 apply
.
可能已经理解了所有这些,我认为最简单的解决方案是嵌套 for
循环。 for 循环 returns 您的值列表,可选择由函数修改。每个值都是一个列表,因此您需要使用另一个 for 循环进行更深入的研究。
; Remove -999's, three levels deep, with for.
(defn remove-999s [s-of-s]
; All data
(for [year s-of-s]
; For all years
(for [month year]
; For all months
; (filter #(not (= % -999)) month) would also work
(remove #(= % -999) month))))
(remove-999s '(((-15 7 15 -25 -5 -45 12 47 56 28 20 40 57 38 2 5 25 -3 0 7 7 -3 -10 -10 30 85 46 77 56 -999 -999) (0 17 -28 -23 -30 5 -18 -3 -33 -23 -18 -3 -10 50 82 72 62 42 15 57 75 40 92 52 42 62 72 70 -999 -999 -999) (-2 -12 4 28 12 0 44 27 -12 16 74 61 76 87 77 78 51 51 59 56 64 52 78 63 39 28 33 81 -999 -999 -999) (97 58 75 103 33 46 88 101 56 47 66 36 52 47 58 42 42 37 63 77 76 43 55 85 58 57 55 66 -999 -999 -999)(-59 19 28 55 47 30 52 49 42 50 45 25 34 70 40 54 24 13 25 54 85 29 27 38 25 73 44 50 40 -999 -999))))
这是结果,没有 -999。
; (((-15 7 15 -25 -5 -45 12 47 56 28 20 40 57 38 2 5 25 -3 0 7 7 -3 -10 -10 30 85 46 77 56)
; (0 17 -28 -23 -30 5 -18 -3 -33 -23 -18 -3 -10 50 82 72 62 42 15 57 75 40 92 52 42 62 72 70)
; (-2 -12 4 28 12 0 44 27 -12 16 74 61 76 87 77 78 51 51 59 56 64 52 78 63 39 28 33 81)
; (97 58 75 103 33 46 88 101 56 47 66 36 52 47 58 42 42 37 63 77 76 43 55 85 58 57 55 66)
; (-59 19 28 55 47 30 52 49 42 50 45 25 34 70 40 54 24 13 25 54 85 29 27 38 25 73 44 50 40))) [End of data]
因为 Clojure 不允许嵌套 #'s,并且嵌套 fn
's 变得很恶心,如果你想像 Biped 建议的那样使用地图,你可能想要将它与 [=19] 一起使用=] 或 defn
。这是我的做法:
; Remove -999's, three levels deep, with maps.
(defn remove-999s [s-of-s]
(letfn [(is-999 [v] (= v -999))
( map-month [s] (remove is-999 s))
( map-year [s] (map map-month s)) ]
(map map-year s-of-s))) ; Gives the same results.
写到这里,才发现for
有点怪怪的map
,两个都可以用
另一种选择的 loop
和 recur
或其他经典递归。
(require '[com.rpl.specter :as s])
(def data '(your list here))
(s/setval (s/walker #(= % -999)) s/NONE data)
我将从效用函数开始,更新任何级别的嵌套序列。
它可能看起来像这样:
(defn update-nested [level f]
(cond (neg? level) identity
(zero? level) f
:else (partial map (update-nested (dec level) f))))
user> ((update-nested 0 (partial remove #{1})) [1 1 0 1])
;;=> (0)
user> ((update-nested 1 (partial remove #{1})) [[1 1 0 1] [0 0 1 0]])
;;=> ((0) (0 0 0))
user> ((update-nested 2 (partial remove #{1})) [[[1 1] [0 1]] [[0 0] [1 0]]])
;;=> ((() (0)) ((0 0) (0)))
user> ((update-nested 3 (partial remove #{1})) [[[[1 1] [0 1]]] [[[0 0] [1 0]]]])
;;=> (((() (0))) (((0 0) (0))))
user> ((update-nested 3 reverse) [[[[1 1] [0 1]]] [[[0 0] [1 0]]]])
;;=> ((((1 1) (1 0))) (((0 0) (0 1))))
我是 Clojure 的初学者,所以我会尽我所能来表达这一点,
我有一个函数 returns 嵌套列表的列表 在解析了每日温度数据集之后, 每个嵌套列表对应于特定月份的每日临时工,例如 2014 年 2 月、2015 年 2 月等,并使用“-999”作为填充符填充到 31 个项目以保留数据集的结构。
原始数据集:https://www.metoffice.gov.uk/hadobs/hadcet/cetdl1772on.dat
(partition 31 (monthly-helper 2 (parse-into-list "CETdataDailyLong")))
=>((-15 7 15 -25 -5 -45 12 47 56 28 20 40 57 38 2 5 25 -3 0 7 7 -3 -10 -10 30 85 46 77 56 -999 -999)
(0 17 -28 -23 -30 5 -18 -3 -33 -23 -18 -3 -10 50 82 72 62 42 15 57 75 40 92 52 42 62 72 70 -999 -999 -999)
(-2 -12 4 28 12 0 44 27 -12 16 74 61 76 87 77 78 51 51 59 56 64 52 78 63 39 28 33 81 -999 -999 -999)
(97 58 75 103 33 46 88 101 56 47 66 36 52 47 58 42 42 37 63 77 76 43 55 85 58 57 55 66 -999 -999 -999)
(-59 19 28 55 47 30 52 49 42 50 45 25 34 70 40 54 24 13 25 54 85 29 27 38 25 73 44 50 40 -999 -999))
我正在尝试从列表中的所有嵌套列表中删除 -999 值,我需要在对数据进行分区后执行此操作,以避免必须按每个月的天数任意对数据进行分区。 我得到的最接近的是下面但它没有效果,因为它只应用于顶级列表而不是每个嵌套列表中的值,我需要如何修改它以获得我正在寻找的结果,或者问我原来的问题; 如何将函数应用于特定嵌套级别的值?
(remove #(= -999 %)(partition 31 (monthly-helper 2 (parse-into-list "CETdataDailyLong"))))
下面是我的分区函数的大部分结果的最小代码,我认为它非常接近,但如果你能告诉我我遗漏了什么,我将非常感激,谢谢
(remove #(= -999 %)'(((-15 7 15 -25 -5 -45 12 47 56 28 20 40 57 38 2 5 25 -3 0 7 7 -3 -10 -10 30 85 46 77 56 -999 -999)
(0 17 -28 -23 -30 5 -18 -3 -33 -23 -18 -3 -10 50 82 72 62 42 15 57 75 40 92 52 42 62 72 70 -999 -999 -999)
(-2 -12 4 28 12 0 44 27 -12 16 74 61 76 87 77 78 51 51 59 56 64 52 78 63 39 28 33 81 -999 -999 -999)
(97 58 75 103 33 46 88 101 56 47 66 36 52 47 58 42 42 37 63 77 76 43 55 85 58 57 55 66 -999 -999 -999)
(-59 19 28 55 47 30 52 49 42 50 45 25 34 70 40 54 24 13 25 54 85 29 27 38 25 73 44 50 40 -999 -999))))
我已经尝试了下面的方法,并使用地图等对其进行了多种变体,但一无所获,看到一个正确的例子真的会帮助我理解我哪里出错了。
(apply #(remove -999 %) (partition 31 (monthly-helper 2 (parse-into-list "CETdataDailyLong"))))
Exception: Wrong number of args (21) passed
您的第一个展览是一个列表列表。您想要的输出也是一个列表列表——但列表不同。因此,您需要 map
而不是 apply
。
所以 iiuc, the:
- 总表包含年份表,
- 年份列表包含月份列表,
- 月份列表包含当天的温度,
- 每个月份列表都用 -999 填充以使其大小统一:31 个条目长
我看到你已经尝试过:
- 您已使用带谓词的
remove
函数在值等于 -999 时删除。本例中的值是'((-15 7 15 -25 -5 -45 12 ...))
,它不等于 -999,所以你最终得到的是你开始时的值。 apply
采用函数和 单个参数序列 。您将 21 个列表传递给apply
.
可能已经理解了所有这些,我认为最简单的解决方案是嵌套 for
循环。 for 循环 returns 您的值列表,可选择由函数修改。每个值都是一个列表,因此您需要使用另一个 for 循环进行更深入的研究。
; Remove -999's, three levels deep, with for.
(defn remove-999s [s-of-s]
; All data
(for [year s-of-s]
; For all years
(for [month year]
; For all months
; (filter #(not (= % -999)) month) would also work
(remove #(= % -999) month))))
(remove-999s '(((-15 7 15 -25 -5 -45 12 47 56 28 20 40 57 38 2 5 25 -3 0 7 7 -3 -10 -10 30 85 46 77 56 -999 -999) (0 17 -28 -23 -30 5 -18 -3 -33 -23 -18 -3 -10 50 82 72 62 42 15 57 75 40 92 52 42 62 72 70 -999 -999 -999) (-2 -12 4 28 12 0 44 27 -12 16 74 61 76 87 77 78 51 51 59 56 64 52 78 63 39 28 33 81 -999 -999 -999) (97 58 75 103 33 46 88 101 56 47 66 36 52 47 58 42 42 37 63 77 76 43 55 85 58 57 55 66 -999 -999 -999)(-59 19 28 55 47 30 52 49 42 50 45 25 34 70 40 54 24 13 25 54 85 29 27 38 25 73 44 50 40 -999 -999))))
这是结果,没有 -999。
; (((-15 7 15 -25 -5 -45 12 47 56 28 20 40 57 38 2 5 25 -3 0 7 7 -3 -10 -10 30 85 46 77 56)
; (0 17 -28 -23 -30 5 -18 -3 -33 -23 -18 -3 -10 50 82 72 62 42 15 57 75 40 92 52 42 62 72 70)
; (-2 -12 4 28 12 0 44 27 -12 16 74 61 76 87 77 78 51 51 59 56 64 52 78 63 39 28 33 81)
; (97 58 75 103 33 46 88 101 56 47 66 36 52 47 58 42 42 37 63 77 76 43 55 85 58 57 55 66)
; (-59 19 28 55 47 30 52 49 42 50 45 25 34 70 40 54 24 13 25 54 85 29 27 38 25 73 44 50 40))) [End of data]
因为 Clojure 不允许嵌套 #'s,并且嵌套 fn
's 变得很恶心,如果你想像 Biped 建议的那样使用地图,你可能想要将它与 [=19] 一起使用=] 或 defn
。这是我的做法:
; Remove -999's, three levels deep, with maps.
(defn remove-999s [s-of-s]
(letfn [(is-999 [v] (= v -999))
( map-month [s] (remove is-999 s))
( map-year [s] (map map-month s)) ]
(map map-year s-of-s))) ; Gives the same results.
写到这里,才发现for
有点怪怪的map
,两个都可以用
另一种选择的 loop
和 recur
或其他经典递归。
(require '[com.rpl.specter :as s])
(def data '(your list here))
(s/setval (s/walker #(= % -999)) s/NONE data)
我将从效用函数开始,更新任何级别的嵌套序列。 它可能看起来像这样:
(defn update-nested [level f]
(cond (neg? level) identity
(zero? level) f
:else (partial map (update-nested (dec level) f))))
user> ((update-nested 0 (partial remove #{1})) [1 1 0 1])
;;=> (0)
user> ((update-nested 1 (partial remove #{1})) [[1 1 0 1] [0 0 1 0]])
;;=> ((0) (0 0 0))
user> ((update-nested 2 (partial remove #{1})) [[[1 1] [0 1]] [[0 0] [1 0]]])
;;=> ((() (0)) ((0 0) (0)))
user> ((update-nested 3 (partial remove #{1})) [[[[1 1] [0 1]]] [[[0 0] [1 0]]]])
;;=> (((() (0))) (((0 0) (0))))
user> ((update-nested 3 reverse) [[[[1 1] [0 1]]] [[[0 0] [1 0]]]])
;;=> ((((1 1) (1 0))) (((0 0) (0 1))))