-
Notifications
You must be signed in to change notification settings - Fork 1
/
5_hashes.clj
174 lines (141 loc) · 4.52 KB
/
5_hashes.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
;; @@PLEAC@@_5.0 Introduction
(ns pleac-section-5
(:require [clojure.java.io :as io]
[clojure.string :as string]))
;; The commas are whitespace and optional. Maps are printed with them
;; at the REPL for readability.
(def age {"Nat" 24, "Jules" 25, "Josh" 17})
(def age (assoc age "Nat" 24))
(def age (assoc age "Jules" 25))
(def age (assoc age "Josh" 17))
;; Commas omitted here.
(def food-color {"Apple" "red"
"Banana" "yellow"
"Lemon" "yellow"
"Carrot" "orange"})
;; @@PLEAC@@_5.1 Adding an Element to a Hash
;; Maps, like all core Clojure data structures, are immutable.
;; Functions for "changing" maps just return new maps.
(def food-color (assoc food-color "Raspberry" "pink"))
(println "Known foods:")
(doseq [food (keys food-color)]
(println food))
;; Known foods:
;; Carrot
;; Banana
;; Raspberry
;; Lemon
;; Apple
;; @@PLEAC@@_5.2 Testing for the Presence of a Key in a Hash
(if (contains? food-color "key")
"exists"
"doesn't exist")
(doseq [name ["Banana" "Martini"]]
(if (contains? food-color name)
(println name "is a food.")
(println name "is a drink.")))
;; Banana is a food.
;; Martini is a drink.
(def age {})
(def age (assoc age "Toddler" 3))
(def age (assoc age "Unborn" 0))
(def age (assoc age "Phantasm" nil))
;; Maps are functions from keys to values, and can be called exactly
;; like functions, taking a key as an argument. The function call
;; returns nil if the key doesn't exist. This works just like using
;; the function "get".
(doseq [thing ["Toddler" "Unborn" "Phantasm" "Relic"]]
(printf "%s: " thing)
(when (contains? age thing) (print "Exists "))
;; get returns nil when the key isn't in the map, and when the key
;; does exist and the value is nil.
(when (get age thing) (print "Defined "))
;; This works just like the above. Output differs from Perl because
;; 0 is not falsy.
(when (age thing) (print "True "))
(newline))
;; Toddler: Exists Defined True
;; Unborn: Exists Defined True
;; Phantasm: Exists
;; Relic:
(defn file-sizes [files]
(reduce (fn [map file]
(let [file (.trim file)]
(if (contains? map file)
map
(assoc map file (.length (java.io.File. file))))))
{}
files))
(file-sizes (line-seq (io/reader *in*)))
;; @@PLEAC@@_5.3 Deleting from a Hash
;; dissoc is used to "remove" (return a new map without the key)
(defn print-foods []
(println "Keys:" (string/join " " (keys food-color)))
(print "Values: ")
(doseq [food (keys food-color)]
(if (food-color food)
(printf "%s " (food-color food))
(print "(undef) ")))
(newline))
(println "Initially:")
(print-foods)
(println "\nWith Banana undef")
(def food-color (assoc food-color "Banana" nil))
(print-foods)
(println "\nWith Banana deleted")
(def food-color (dissoc food-color "Banana"))
(print-foods)
;; Initially:
;; Keys: Carrot Banana Lemon Apple
;; Values: orange yellow yellow red
;; With Banana undef
;; Keys: Carrot Banana Lemon Apple
;; Values: orange (undef) yellow red
;; With Banana deleted
;; Keys: Carrot Lemon Apple
;; Values: orange yellow red
(def food-color (dissoc food-color "Banana" "Apple" "Cabbage"))
;; @@PLEAC@@_5.4 Traversing a Hash
(doseq [[key value] food-color]
;; do something
)
(doseq [key (keys food-color)]
(let [value (food-color key)]
;; do something
))
;; food-color per the introduction
(doseq [[food color] food-color]
(printf "%s is %s.\n" food color))
;; Carrot is orange.
;; Banana is yellow.
;; Lemon is yellow.
;; Apple is red.
(doseq [food (keys food-color)]
(let [color (food-color food)]
(printf "%s is %s.\n" food color)))
;; Carrot is orange.
;; Banana is yellow.
;; Lemon is yellow.
;; Apple is red.
(doseq [food (sort (keys food-color))]
(let [color (food-color food)]
(printf "%s is %s.\n" food color)))
;; Apple is red.
;; Banana is yellow.
;; Carrot is orange.
;; Lemon is yellow.
;; There isn't an idiomatic way to reset an iteration through a
;; collection in Clojure.
(defn countfrom [file]
(with-open [rdr (io/reader file)]
(let [lines (line-seq rdr)
match-sender (fn [line]
(second (re-matches #"^From: (.*)" line)))
from (reduce (fn [map line]
(let [sender (match-sender line)
cur (get map sender 0)]
(assoc map sender (inc cur))))
{}
lines)]
(doseq [[person n] (sort from)]
(printf "%s: %d\n" person n)))))