-
Notifications
You must be signed in to change notification settings - Fork 0
/
maps.html
executable file
·355 lines (344 loc) · 27.4 KB
/
maps.html
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- Generated by Apache Maven Doxia Site Renderer 1.3 at May 19, 2012 -->
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>op4j: bending the Java spoon - Working with maps</title>
<style type="text/css" media="all">
@import url("./css/maven-base.css");
@import url("./css/maven-theme.css");
@import url("./css/site.css");
</style>
<link rel="stylesheet" href="./css/print.css" type="text/css" media="print" />
<meta name="Date-Revision-yyyymmdd" content="20120519" />
<meta http-equiv="Content-Language" content="en" />
</head>
<body class="composite">
<div id="banner">
<a href="./" id="bannerLeft">
<img src="images/op4j_logo.png" alt="op4j: bending the Java spoon" />
</a>
<div class="clear">
<hr/>
</div>
</div>
<div id="breadcrumbs">
<div class="xleft">
<span id="publishDate">Last Published: 19 May 2012</span>
| <span id="projectVersion">Version: 1.2</span>
</div>
<div class="xright"> <a href="index.html" title="Main">Main</a>
|
<a href="download.html" title="Download">Download</a>
|
<a href="https://www.bendingthejavaspoon.com" class="externalLink" title="Example Recipes Blog">Example Recipes Blog</a>
|
<a href="https://github.com/op4j/op4j.github.com/issues" class="externalLink" title="Issue Tracking">Issue Tracking</a>
|
<a href="apidocs/index.html" title="Javadoc">Javadoc</a>
|
<a href="https://github.com/op4j" class="externalLink" title="Github Project Page">Github Project Page</a>
</div>
<div class="clear">
<hr/>
</div>
</div>
<div id="leftColumn">
<div id="navcolumn">
<h5>The op4j Project</h5>
<ul>
<li class="none">
<a href="index.html" title="· Main">· Main</a>
</li>
<li class="none">
<a href="download.html" title="· Download">· Download</a>
</li>
<li class="none">
<a href="maveninfo.html" title="· Maven Info">· Maven Info</a>
</li>
<li class="none">
<a href="dependencies.html" title="· Dependencies">· Dependencies</a>
</li>
<li class="none">
<a href="https://github.com/op4j" class="externalLink" title="· Github Repository">· Github Repository</a>
</li>
<li class="none">
<a href="https://www.bendingthejavaspoon.com" class="externalLink" title="· Example Recipes">· Example Recipes</a>
</li>
<li class="none">
<a href="https://github.com/op4j/op4j.github.com/issues" class="externalLink" title="· Issue Tracking">· Issue Tracking</a>
</li>
<li class="expanded">
<a href="#" title="· Documentation">· Documentation</a>
<ul>
<li class="none">
<a href="basics.html" title="· The Basics">· The Basics</a>
</li>
<li class="expanded">
<a href="#" title="· Working with...">· Working with...</a>
<ul>
<li class="none">
<a href="arrays.html" title="· Arrays">· Arrays</a>
</li>
<li class="none">
<a href="lists.html" title="· Lists">· Lists</a>
</li>
<li class="none">
<strong>· Maps</strong>
</li>
<li class="none">
<a href="sets.html" title="· Sets">· Sets</a>
</li>
<li class="none">
<a href="generic.html" title="· Any object (generic)">· Any object (generic)</a>
</li>
</ul>
</li>
<li class="expanded">
<a href="#" title="· Functions">· Functions</a>
<ul>
<li class="none">
<a href="functions.html" title="· About Functions">· About Functions</a>
</li>
<li class="none">
<a href="call.html" title="· Call">· Call</a>
</li>
<li class="none">
<a href="get.html" title="· Get">· Get</a>
</li>
<li class="none">
<a href="fnfunc.html" title="· FnFunc">· FnFunc</a>
</li>
<li class="none">
<a href="fnboolean.html" title="· FnBoolean">· FnBoolean</a>
</li>
<li class="none">
<a href="fncalendar.html" title="· FnCalendar">· FnCalendar</a>
</li>
<li class="none">
<a href="fndate.html" title="· FnDate">· FnDate</a>
</li>
<li class="none">
<a href="fnobject.html" title="· FnObject">· FnObject</a>
</li>
<li class="none">
<a href="fnstring.html" title="· FnString">· FnString</a>
</li>
<li class="expanded">
<a href="#" title="· Numbers">· Numbers</a>
<ul>
<li class="none">
<a href="fnnumber.html" title="· FnNumber">· FnNumber</a>
</li>
<li class="none">
<a href="fnbigdecimal.html" title="· FnBigDecimal">· FnBigDecimal</a>
</li>
<li class="none">
<a href="fnbiginteger.html" title="· FnBigInteger">· FnBigInteger</a>
</li>
<li class="none">
<a href="fninteger.html" title="· FnInteger">· FnInteger</a>
</li>
<li class="none">
<a href="fnlong.html" title="· FnLong">· FnLong</a>
</li>
<li class="none">
<a href="fnfloat.html" title="· FnFloat">· FnFloat</a>
</li>
<li class="none">
<a href="fndouble.html" title="· FnDouble">· FnDouble</a>
</li>
<li class="none">
<a href="fndouble.html" title="· FnShort">· FnShort</a>
</li>
</ul>
</li>
<li class="expanded">
<a href="#" title="· Structures">· Structures</a>
<ul>
<li class="none">
<a href="fnarray.html" title="· FnArray">· FnArray</a>
</li>
<li class="none">
<a href="fnlist.html" title="· FnList">· FnList</a>
</li>
<li class="none">
<a href="fnmap.html" title="· FnMap">· FnMap</a>
</li>
<li class="none">
<a href="fnset.html" title="· FnSet">· FnSet</a>
</li>
<li class="none">
<a href="fntuple.html" title="· FnTuple">· FnTuple</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="none">
<a href="apidocs/op4j/index.html" title="· Javadoc">· Javadoc</a>
</li>
<li class="none">
<a href="faq.html" title="· FAQ">· FAQ</a>
</li>
</ul>
</li>
<li class="none">
<a href="license.html" title="· License">· License</a>
</li>
<li class="none">
<a href="team.html" title="· Team">· Team</a>
</li>
</ul>
<ul>
<li class="collapsed">
<a href="ognl-about.html" title="· op4j-ognl">· op4j-ognl</a>
</li>
<li class="collapsed">
<a href="jodatime-about.html" title="· op4j-jodatime">· op4j-jodatime</a>
</li>
</ul>
<a href="https://maven.apache.org" title="Built with Maven 2" class="poweredBy">
<img class="poweredBy" alt="Built with Maven 2" src="https://maven.apache.org/images/logos/maven-feather.png" />
</a>
</div>
</div>
<div id="bodyColumn">
<div id="contentBox">
<div class="section"><h2>Working with maps<a name="Working_with_maps"></a></h2><p>This page explains how op4j can deal with map objects (objects implementing <tt>java.util.Map<K,V></tt>).</p><p>Map input objects are considered immutable, so they will not be changed when used in an op4j expression and a new map will always be returned when executing <tt>get()</tt>.</p><p>This, however, does not apply to the input map key and value objects, which could be changed if you executed on them any functions which might change their state instead of substituting them for new elements.</p><ul><li><a href="#a1">Creating map expressions</a></li><li><a href="#a2">Extracting keys and values</a></li><li><a href="#a3">Iterating</a></li><li><a href="#a4">Modifying</a></li><li><a href="#a5">Executing functions</a></li><li><a href="#a6">Selecting (conditional code)</a></li><li><a href="#a7">Replacing</a></li><li><a href="#a8">Reversing</a></li></ul><div class="section"><h3><a name="a1">1</a>. Creating map expressions<a name="a1._Creating_map_expressions"></a></h3><div class="section"><h4>Operation expressions<a name="Operation_expressions"></a></h4><p>There are two equivalent ways of creating an operation expression on a map. Just use the method you like most:</p><div class="source"><pre>Map<String,String> map = ...;
Op.on(map)...
</pre></div><div class="source"><pre>Map<String,String> map = ...;
Op.onMap(map)...
</pre></div><div class="section"><h5>Maps from their elements<a name="Maps_from_their_elements"></a></h5><p>Map expressions can be created by specifying the map elements (entries), as <i>key</i>/<i>value</i> pairs, like:</p><div class="source"><pre>Op.onMapFor(key1, value1).and(key2, value2).and(key3, value3)...
</pre></div><p>Once any action is called, the <tt>and(...)</tt> method will not be available anymore, as it is only meant to <i>build</i> the map. </p></div><div class="section"><h5>Maps from arrays, lists or sets. <a name="Maps_from_arrays_lists_or_sets."></a></h5><p>Maps can be built from arrays, lists or sets in a variety of ways (see the <a href="./arrays.html">arrays</a>, <a href="./lists.html">lists</a> or <a href="./sets.html">sets</a> documentation for details).</p><p>For example, zipping can be used:</p><div class="source"><pre> Map<String,Integer> map = Op.onListFor("a","b","c").zipValues(1,2,3).get();
</pre></div></div></div><div class="section"><h4>Function expressions<a name="Function_expressions"></a></h4><p>Function expressions are created as usual with other structures:</p><div class="source"><pre>// Create a function which receives a Map<Integer,String> variable as input
function = Fn.onMapOf(Types.INTEGER, Types.STRING)...get();
</pre></div></div></div><div class="section"><h3><a name="a2">2</a>. Extracting keys and values<a name="a2._Extracting_keys_and_values"></a></h3><p>All keys of a map can be extracted as a Set:</p><div class="source"><pre>Map<Integer,String> map =
Set<Integer> keys = Op.on(map).extractKeys().get();
</pre></div><p>Also values can be extracted, as a List:</p><div class="source"><pre>Map<Integer,String> map =
List<String> values = Op.on(map).extractValues().get();
</pre></div></div><div class="section"><h3><a name="a3">3</a>. Iterating<a name="a3._Iterating"></a></h3><p>Maps can be iterated, resulting in an operator acting on its <i>map entries</i> (<tt>Map.Entry<K,V></tt>).</p><div class="source"><pre>Op.on(map).forEachEntry()...
</pre></div><p>And once iterating each entry, actions can be executed on the entry itself (having thus access to both key and value):</p><div class="source"><pre>Op.on(map).forEachEntry().[ACTIONS ON MAP ENTRIES]...
</pre></div><p>But also the keys can be selected, so that subsequent actions will only apply on the map's keys:</p><div class="source"><pre>Op.on(map).forEachEntry().onKey().[ACTIONS ON MAP KEYS]...
</pre></div><p>...and the same for the values:</p><div class="source"><pre>Op.on(map).forEachEntry().onValue().[ACTIONS ON MAP VALUES]...
</pre></div><p>The result obtained when executing <tt>get()</tt> after iterating will be a map with the results of applying the subsequently chained actions on the entries/keys/values of the map. </p><p>Iteration on entries can be ended with the <tt>endFor()</tt> action:</p><div class="source"><pre>Op.on(map).forEachEntry().[ENTRY ACTIONS].endFor().[MAP ACTIONS].get();
</pre></div><p>And selection of keys or values can be ended with the <tt>endOn()</tt> action:</p><div class="source"><pre>Op.on(map).forEachEntry().onKey().[KEY ACTIONS].endOn().endFor().[MAP ACTIONS].get();
Op.on(map).forEachEntry().onValue().[VALUE ACTIONS].endOn().endFor().[MAP ACTIONS].get();
</pre></div></div><div class="section"><h3><a name="a4">4</a>. Modifying<a name="a4._Modifying"></a></h3><p>A map can be modified by adding or removing elements from it. </p><p>Maps in op4j are ordered (<tt>LinkedHashMap</tt>), and several options for adding new elements at the end of a map:</p><div class="source"><pre>Map<String,String> map = ...;
Map<String,String> newElements = ...;
...
Op.on(map).put("new Key", "new Value")...
Op.on(map).putAll(newElements)...
</pre></div><p>New elements can also be inserted into a specific position. Positions start with 0.</p><div class="source"><pre>Map<String,String> map = ...;
Map<String,String> newElements = ...;
...
Op.on(map).insert(0, "new Key", "new Value")...
Op.on(map).insertAll(0, newElements)...
</pre></div><p>Removal of elements can be done in several ways. Elements can be removed attending to their keys:</p><div class="source"><pre>Op.on(map).removeAllKeys("one Key", "another Key")...
Op.on(map).removeAllKeysNot("one Key", "another Key")...
</pre></div><p>A function returning <tt>Boolean</tt> can be used as evaluator to determine whether an element should be removed or not:</p><div class="source"><pre>Map<String,String> map = ...;
IFunction<Map.Entry<String,String>,Boolean> eval = ...;
...
Op.on(map).removeAllTrue(eval)...
Op.on(map).removeAllFalse(eval)...
</pre></div></div><div class="section"><h3><a name="a5">5</a>. Executing functions<a name="a5._Executing_functions"></a></h3><div class="section"><h4>Executing functions on the map keys or values<a name="Executing_functions_on_the_map_keys_or_values"></a></h4><p>Functions can be executed on each of the map keys or values after a <i>forEachEntry()</i> followed by and an <i>onKey()</i> or <i>onValue()</i> action:</p><div class="source"><pre>Map<String,String> map = ...;
...
Map<String,String> newMap =
Op.on(map).forEachEntry().onValue().exec(FnString.toUpperCase()).get();
</pre></div><p>A condition can be added for conditional execution, if needed:</p><div class="source"><pre>Map<String,String> map = ...;
IFunction<String,String> myFunction = ...;
...
Map<String,String> newMap =
Op.on(map).forEachEntry().onValue().execIfNotNull(myFunction).get();
</pre></div><div class="source"><pre>Map<String,String> map = ...;
IFunction<String,Boolean> condition = ...;
IFunction<String,String> myFunction = ...;
...
Op.on(map).forEachEntry().onValue().execIfTrue(condition, myFunction)...
</pre></div><p>...an <i>else</i> side can it also be added, in which case the expression can change the type of the operator: </p><div class="source"><pre>Map<String,String> map = ...;
IFunction<String,Boolean> condition = ...;
IFunction<String,Integer> myThenFunction = ...;
IFunction<String,Integer> myElseFunction = ...;
...
Map<String,Integer> newMap = ...;
Op.on(map).forEachEntry().onValue().execIfTrue(condition, myThenFunction, myElseFunction).get();
</pre></div></div><div class="section"><h4>Executing functions on map entries<a name="Executing_functions_on_map_entries"></a></h4><p>Functions can be executed on entire map entries. </p><p>These functions can return <tt>Map.Entry<K,V></tt> objects as well, in which case the target object will be still considered a map:</p><div class="source"><pre>Map<String,String> map = ...;
IFunction<Map.Entry<String,String>,Map.Entry<String,String>> myFunction = ...;
...
Map<String,String> newMap =
Op.on(map).forEachEntry().execAsMapEntry(myFunction).get();
</pre></div><p>...or they can return something different from a map entry, in which case the target object will be considered a List from then on:</p><div class="source"><pre>Map<String,String> map = ...;
IFunction<Map.Entry<String,String>,Integer> myFunction = ...;
...
List<Integer> newList =
Op.on(map).forEachEntry().exec(myFunction).get();
</pre></div></div><div class="section"><h4>Executing functions on the whole map<a name="Executing_functions_on_the_whole_map"></a></h4><p>If a map has not been iterated (<i>forEach()</i>) (or it has, but <i>endFor()</i> has been called), functions can be executed on the whole map. </p><p>There are three ways of executing functions on a map as a whole:</p><ul><li>Executions which return a map (example: Map<String,String> -> Map<String,Integer>)</li><li>Executions which do not return a map (example: Map<String,String> -> Calendar)</li></ul><div class="section"><h5>Returning a map<a name="Returning_a_map"></a></h5><p>Functions will be executed using the <tt>execAsMap(...)</tt> action:</p><div class="source"><pre>Map<String,String> map = ...;
IFunction<Map<String,String>,Map<String,Integer>> myFunction = ...;
...
Op.on(map).execAsMap(myFunction)...
</pre></div><p>A conditional check can be added (null, not null, condition true, condition false): </p><div class="source"><pre>Map<String,String> map = ...;
IFunction<Map<String,String>,Map<String,Integer>> myFunction = ...;
...
Op.on(map).execIfNotNullAsMap(myFunction)...
</pre></div></div><div class="section"><h5>Not returning a map<a name="Not_returning_a_map"></a></h5><div class="source"><pre>Map<String,String> map = ...;
IFunction<Map<String,String>,Calendar> myFunction = ...;
...
Calendar calendar = Op.on(map).exec(myFunction).get();
</pre></div></div></div></div><div class="section"><h3><a name="a6">6</a>. Selecting (conditional code)<a name="a6._Selecting_conditional_code"></a></h3><p>op4j allows the conditional execution of actions. Once the condition (an action starting with "<tt>if</tt>") is executed, all subsequent actions will apply only on the selected parts of the target object.</p><p>For example, lets convert into upper case only the first String key of the map:</p><div class="source"><pre>Map<String,String> map = ...;
Map<String> newMap = Op.on(map).forEachEntry().ifIndex(0).onKey().exec(FnString.toUpperCase()).get();
</pre></div><p>Selections can be ended with <tt>endIf(...)</tt>:</p><div class="source"><pre>Map<String> newMap =
Op.on(map).forEachEntry().ifIndex(0,1,3).[ACTIONS ON SELECTED ENTRIES].endIf()...
</pre></div><div class="section"><h4>Selecting specific map keys/values <a name="Selecting_specific_map_keysvalues"></a></h4><p>If a selection is executed after <i>forEachEntry().onKey()</i> or <i>forEachEntry().onValue()</i>, it will be applied on the map keys or values, respectively.</p><p>Selection can be based on the nullity of the element: </p><div class="source"><pre>Op.on(map).forEachEntry().onValue().ifNull()....
Op.on(map).forEachEntry().onValue().ifNotNull()....
</pre></div><p>And also on the value returned by the evaluation of a function returning <tt>Boolean</tt>:</p><div class="source"><pre>Map<String,String> map = ...;
IFunction<String,Boolean> eval = ...;
...
Op.on(map).forEachEntry().onValue().ifTrue(eval)...
Op.on(map).forEachEntry().onValue().ifFalse(eval)...
</pre></div></div><div class="section"><h4>Selecting specific map entries <a name="Selecting_specific_map_entries"></a></h4><p>If a selection is executed after a <i>forEachEntry()</i> action without <i>onKey()</i> or <i>onValue()</i> being executed, it will be applied on the map entries.</p><p>Selection can be done on the entry's position in the map:</p><div class="source"><pre>Op.on(map).forEachEntry().ifIndex(0,2,3)....
Op.on(map).forEachEntry().ifIndexNot(0,1,5)....
</pre></div><p>...on the value of its key:</p><div class="source"><pre>Op.on(map).forEachEntry().ifKeyEquals("a key", "another key")....
Op.on(map).forEachEntry().ifKeyNotEquals("a key", "another key")....
</pre></div><p>...and also on the value returned by the evaluation of a function returning <tt>Boolean</tt>:</p><div class="source"><pre>Map<String,String> map = ...;
IFunction<Map.Entry<String,String>,Boolean> eval = ...;
...
Op.on(map).forEachEntry().ifTrue(eval)...
Op.on(map).forEachEntry().ifFalse(eval)...
</pre></div></div><div class="section"><h4>Selecting the map as a whole <a name="Selecting_the_map_as_a_whole"></a></h4><p>Selection can also be performed on the map itself as a whole, effectively deciding whether subsequent actions will be executed at all or not. </p><div class="source"><pre>Map<String,String> map = ...;
IFunction<Map<String,String>,Boolean> eval = ...;
...
Op.on(map).ifNull()....
Op.on(map).ifNotNull()....
Op.on(map).ifTrue(eval)...
Op.on(map).ifFalse(eval)...
</pre></div></div><div class="section"><h4>Restricions on execution actions after selection<a name="Restricions_on_execution_actions_after_selection"></a></h4><p>After executing a selection action, function executed by means of an <i>exec</i> action cannot change the map key and/or value types (i.e., a <tt>Map<String,String></tt> must remain <tt>Map<String,String></tt>.</p><p>So this would not be valid:</p><div class="source"><pre>// Will not compile!
Map<String,String> newMap =
Op.on(map).forEachEntry().ifIndex(0,1,3).onKey().exec(FnString.toInteger()).get();
</pre></div><p>...because converting only <i>some</i> of the map keys to integer would render the map type inconsistent (some elements would be <tt>String</tt>, some other <tt>Integer</tt>).</p><p>This is perfectly valid, though:</p><div class="source"><pre>// FnString.toUpperCase is IFunction<String,String>
Map<String,String> newMap =
Op.on(map).forEachEntry().ifIndex(0,1,3).onKey().exec(FnString.toUpperCase()).get();
</pre></div></div></div><div class="section"><h3><a name="a7">7</a>. Replacing<a name="a7._Replacing"></a></h3><p>Map keys, values, entries or even the map itself can be replaced by other objects:</p><div class="source"><pre>Map<String,String> newMap =
Op.on(map).forEachEntry().onValue().ifNull().replaceWith("[no value]").get();
</pre></div><p>...which is equivalent to:</p><div class="source"><pre>Map<String,String> newMap =
Op.on(map).forEachEntry().onValue().replaceIfNullWith("[no value]").get();
</pre></div></div><div class="section"><h3><a name="a8">8</a>. Reversing<a name="a8._Reversing"></a></h3><p>Maps can be reversed, so that the order of its entries gets inverted:</p><div class="source"><pre> // map = {{"a"=1},{"b"=2},{"c"=3}}
// newMap = {{"c"=3},{"b"=2},{"a"=1}}
Map<String,Integer> newMap = Op.on().reverse().get();
</pre></div></div></div>
</div>
</div>
<div class="clear">
<hr/>
</div>
<div id="footer">
<div class="xright">
Copyright © 2012
<a href="https://www.op4j.org">The OP4J team</a>.
All Rights Reserved.
</div>
<div class="clear">
<hr/>
</div>
</div>
</body>
</html>