Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bacdfe8

Browse files
author
Ryan Neufeld
committed
Editing of retrieving-multiple-keys
1 parent 470b560 commit bacdfe8

File tree

3 files changed

+55
-65
lines changed

3 files changed

+55
-65
lines changed

composite-data/maps/retrieving-keys/retrieving-keys.asciidoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
[[sec_composite_retrieving_keys_map]]
12
=== Retrieving keys from a map
23
[role="byline"]
34
by Luke VanderHart

composite-data/maps/retrieving-multiple-keys/retrieving-multiple-keys.asciidoc

Lines changed: 52 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -5,102 +5,91 @@ by Leonardo Borges
55

66
==== Problem
77

8-
You want to get the values of several keys in a map in one go.
8+
You want to retrieve multiple values from a map at one time.
99

1010
==== Solution
1111

12-
Before we start, define a map from which you wish to pick values:
12+
Use +vals+ and +select-keys+ when the order of returned values is not
13+
important.
1314

1415
[source,clojure]
1516
----
16-
(def character {:name "Galdalf"
17-
:race "Maiar"
18-
:culture "Wizards"
19-
:gender "Male"
20-
:weapon "Wizard Staff"})
21-
----
22-
23-
There are mainly two ways you can go about solving this problem. The first is more
24-
likely to be seen in the wild as it uses the all too familiar functions +vals+ and +select-keys+.
17+
;; How many red and green beans are there?
18+
(def beans {:red 10
19+
:blue 3
20+
:green 1})
2521
26-
27-
[source,clojure]
28-
----
29-
(vals (select-keys character [:name :culture :weapon]))
30-
;; ("Wizard Staff" "Wizards" "Galdalf")
22+
(reduce + (vals (select-keys beans [:red :green])))
23+
;; -> 11
3124
----
3225

33-
The second way uses +juxt+ and yields the same results for most use cases while also
34-
being more concise:
26+
Use +juxt+ when order matters.
3527

3628
[source,clojure]
3729
----
38-
((juxt :name :culture :weapon) character)
39-
;; ["Galdalf" "Wizards" "Wizard Staff"]
30+
;; What are the red and green bean totals?
31+
((juxt :red :green) beans)
32+
;; -> [10 1]
4033
----
4134

42-
4335
==== Discussion
4436

45-
Now you might be thinking when to choose one approach over the other.
46-
47-
In most cases it won't matter as both approaches return the same _sequence_ of values. The difference lies in the details.
48-
49-
As you can see above, the result of getting the list of values by using +vals+ doesn't guarantee any type of ordering. This might or might not be a problem depending on what you intend to do with the values. Also note that it returns a _sequence_, whereas +juxt+ returns a _vector_.
37+
+juxt+ and the combination of +vals+ and +select-keys+ are both apt
38+
tools for retrieving multiple keys from a map. There are subtleties to
39+
their behavior that are important to understand.
5040

51-
It's also interesting to note that +select-keys+ receives a sequence of keys.
41+
At first glance the +juxt+ approach seems to be the clear winner of
42+
the two. The +juxt+ approach only goes so far; the approach falls
43+
apart when any of the keys you wish to retrieve is not a keyword (more
44+
specifically, not a *function*.) This is because +juxt+ merely
45+
_juxtaposes_ the return values of multiple functions. Since keywords
46+
are functions, it's possible to +juxt+ them and retrieve a
47+
strongly-ordered list of values.
5248

53-
+juxt+ on the other hand returns the values in the order in which they were provided the function. To see why that is we need to understand how +juxt+ works.
54-
55-
Being a variadic function, +juxt+ accepts one or more arguments. These arguments have to be functions - which is very convenient to us since keywords can be used as functions in Clojure.
56-
57-
Let these functions be +f1+, +f2+ ... +fN+.
58-
59-
The result is itself another variadic function which, when called, returns a vector of the results of applying +f1+, +f2+ ... +fN+ to its arguments, one by one.
60-
61-
A few examples might illustrate this better than I can explain:
49+
If the keys in the +beans+ map were strings, it would not be possible
50+
to retrieve their values with +juxt+.
6251

6352
[source,clojure]
6453
----
65-
;
66-
; Check how vectors and lists respond to various sequence predicates
67-
;
68-
((juxt seq? sequential? vector? list?) [1 2 3 4])
69-
;; [false true true false]
70-
71-
((juxt seq? sequential? vector? list?) '(1 2 3 4))
72-
;; [true true false true]
73-
74-
75-
;
76-
; Sort a vector of maps by composite key
77-
;
78-
(sort-by (juxt :last :first) [{:first "Frodo" :last "Baggins"}
79-
{:first "Bilbo" :last "Baggins"}
80-
{:first "Samwise" :last "Gamgee"}
81-
{:first "Meriadoc" :last "Brandybuck"}])
82-
;; ({:last "Baggins", :first "Bilbo"} {:last "Baggins", :first "Frodo"}
83-
;; {:last "Brandybuck", :first "Meriadoc"} {:last "Gamgee", :first "Samwise"})
54+
((juxt "a" "b") beans)
55+
;; -> ClassCastException java.lang.String cannot be cast to clojure.lang.IFn ...
8456
----
8557

86-
Put another way, our previous example, where we pulled out information about our character:
58+
+select-keys+, on the other hand, *is* capable of pulling values for
59+
any number of arbitrary keys. The +select-keys+ function takes a map
60+
and sequence of keys and returns a new map populated with *only* those
61+
keys.
8762

8863
[source,clojure]
8964
----
90-
((juxt :name :culture :weapon) character)
91-
;; ["Galdalf" "Wizards" "Wizard Staff"]
65+
(def weird-map {"a" 1, {:foo :bar} :baz, 13 31})
66+
67+
(select-keys weird-map
68+
["a" {:foo :bar}])
69+
;; -> {{:foo :bar} :baz, "a" 1}
70+
71+
(vals {{:foo :bar} :baz, "a" 1})
72+
;; -> (1 :baz)
9273
----
9374

94-
Is simply short for:
75+
Since maps are not ordered, it is *not* safe to assume that the
76+
ordering of keys and values is identical (even if you stumble upon an
77+
example where it is.) In cases where you're pulling multiple values
78+
from non-keyword maps it is probably easiest to wrap that interaction
79+
up via +juxt+.
9580

9681
[source,clojure]
9782
----
98-
[(:name character) (:culture character) (:weapon character)]
99-
;; ["Galdalf" "Wizards" "Wizard Staff"]
83+
(def a-str-then-foo-bar-map
84+
(juxt #(get % "a")
85+
#(get % {:foo :bar})))
86+
87+
(a-str-then-foo-bar-map weird-map)
88+
;; -> [1 :baz]
10089
----
10190

102-
+juxt+ is one of those functions that you just got to have up your sleeve. You will not use it often, but when the scenario presents itself, you'll be glad you know about it.
91+
You'll avoid weird maps now, won't you?
10392

10493
==== See also
10594

106-
* Retrieving Keys
95+
* <<sec_composite_retrieving_keys_map>>

primitive-data/strings/find-and-replace/find-and-replace.asciidoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ treat. Regexps are a powerful tool for modifying strings with
7272
unbounded flexibility. Like any powerful new tool, it's easy to
7373
over-do it. Because of their terse and compact syntax it's very easy
7474
to produce regexps that are both difficult to interpret and at a high
75-
risk of being incorrect. We suggest you use regular expressions
76-
sparingly, and only if you fully understand their syntax.
75+
risk of being incorrect. You should regular expressions sparingly, and
76+
only if you fully understand their syntax.
7777

7878
==== See Also
7979

0 commit comments

Comments
 (0)