/
arrays.xml
281 lines (183 loc) · 21.9 KB
/
arrays.xml
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
<?xml version="1.0" encoding="utf-8"?>
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="5.0"
xml:id="arr.arrays"
xml:lang="en">
<title>Arrays</title>
<remark>TODO: #pack</remark>
<para>An <literal>Array</literal> is a mutable, heterogeneous, ordered collection of objects, termed <firstterm>elements</firstterm>, indexed by an <literal>Integer</literal> subscript. Its mutability means that elements can be added to, and removed from, the collection at any point in its lifetime, causing the <literal>Array</literal> to expand or contract as needed. In keeping with her philosophy of duck-typing, Ruby does not require the elements to have a specific type: any permutation of objects may be stored in an <literal>Array</literal>. That each element is indexed by a unique <literal>Integer</literal>, enforces unambiguous order on the collection.</para>
<para>The first element of an <literal>Array</literal> has the index <literal>0</literal>, so the last element has an index one less than the total number of elements. Methods that accept <literal>Array</literal> indices as arguments, interpret negative indices as counting backward from the last element, i.e. <literal>-2</literal> refers to the penultimate element.</para>
<para>The number of elements an <literal>Array</literal> contains is returned by <function>Array#size</function>. When the size is <literal>0</literal>, <function>Array#empty?</function> returns <literal>true</literal>.</para>
<para>Instances of <literal>Array</literal> are <link linkend="enu.enumerables"><literal>Enumerable</literal></link>, so in addition to the methods described in this chapter, they also respond to the <literal>Enumerable</literal> methods.</para>
<sect1 xml:id="arr.literals">
<title>Literals</title>
<para>An <literal>Array</literal> literal is a comma-separated list of expressions enclosed in square brackets (<literal>[</literal>, <literal>]</literal>). For example, <literal>[1, :two, 'three']</literal> creates a three-element <literal>Array</literal> object with <literal>1</literal> as the first element. </para>
<sect2 xml:id="arr.literal-w">
<title>Alternative Delimiters</title>
<para>The <literal>%w<replaceable>delimiter</replaceable>…<replaceable>delimiter</replaceable></literal> construct is a syntactical shortcut for instantiating an array of strings. The delimiters take the same form as those of <link linkend="str.single-quoted-q">%q</link>. The text between them is split on whitespace, each substring becoming an element on the array. <literal>%w</literal> interprets its contents with single-quoted string semantics; its counterpart, <literal>%W</literal>, behaves in the same way using double-quoted string semantics.</para>
<example xml:id="ex.array-literal-w">
<title>Creating an array of strings with the <literal>%w</literal> and <literal>%W</literal> constructs</title>
<programlisting><xi:include href="examples/array-literal-w.rb" parse="text"/></programlisting>
</example>
</sect2>
</sect1>
<sect1 xml:id="arr.new">
<title><literal>Array.new</literal></title>
<para><literal>Array</literal>s are typically instantiated with the literal syntax explained above. <literal>Array.new</literal> offers more control over this process. When called with no arguments it is equivalent to <literal>[]</literal>. <literal>Array.new(<replaceable>size</replaceable>, <replaceable>o</replaceable>)</literal> creates a <replaceable>size</replaceable>-element <literal>Array</literal> with each value set to <replaceable>o</replaceable>. If <replaceable>o</replaceable> is omitted, it defaults to <literal>nil</literal>. When given an <literal>Array</literal> argument, <replaceable>a</replaceable>, it returns <literal>a.to_ary</literal>. Lastly, if a numeric argument, <replaceable>size</replaceable>, and block are provided, the block is called <replaceable>size</replaceable> times, with its return value becoming the corresponding <literal>Array</literal> value.</para>
<example xml:id="ex.array-new">
<title>Creating an <literal>Array</literal> with <literal>Array.new</literal></title>
<programlisting><xi:include href="examples/array-new.rb" parse="text"/></programlisting>
</example>
</sect1>
<sect1 xml:id="arr.lookup">
<title>Lookup</title>
<para>The element at index <replaceable>n</replaceable> can be retrieved with <literal>#[<replaceable>n</replaceable>]</literal>. <literal>#at(<replaceable>n</replaceable>)</literal> and <literal>#slice(<replaceable>n</replaceable>)</literal> behave in the same manner. If the index <replaceable>n</replaceable> lies outside of the array, these methods return <literal>nil</literal>. The <literal>#fetch</literal> method also returns the element at a given index, however it differs from the aforementioned in how it reacts to non-existent indices. <literal>#fetch(<replaceable>n</replaceable>)</literal> raises an <literal>IndexError</literal>, or, if given a block, returns the value of the block when passed <replaceable>n</replaceable>. <literal>#fetch(<replaceable>n</replaceable>, <replaceable>default</replaceable>)</literal> returns <replaceable>default</replaceable>.</para>
<example xml:id="ex.array-lookup-single">
<title>Looking-up a single element in an <literal>Array</literal></title>
<programlisting><xi:include href="examples/array-lookup-single.rb" parse="text"/></programlisting>
</example>
<para>Whereas the methods above returned the element corresponding to a given index, <literal>#index(<replaceable>e</replaceable>)</literal>, or its alias <literal>#find_index(<replaceable>e</replaceable>)</literal> return the index corresponding to a given element. Specifically, <literal>#index(<replaceable>e</replaceable>)</literal> returns the index of the first element <literal>#==</literal> to <literal>e</literal>. If either method is provided a block instead of <replaceable>e</replaceable>, it calls the block with each element in turn, returning the index of the first element for which the block returns <literal>true</literal>. <literal>#rindex</literal> behaves identically to <literal>#index</literal> except it tests the elements in reverse order.</para>
<example xml:id="ex.array-index">
<title>Looking-up an element’s index in an <literal>Array</literal></title>
<programlisting><xi:include href="examples/array-index.rb" parse="text"/></programlisting>
</example>
<para>To lookup multiple elements at once, <literal>#[](<replaceable>start</replaceable>, <replaceable>length</replaceable>)</literal> or <literal>#[](<replaceable>range</replaceable>)</literal>, or its alias, <literal>#slice</literal>, can be used. The first form returns an <literal>Array</literal> of at most <replaceable>length</replaceable> consecutive elements, beginning at index <replaceable>start</replaceable>. The second returns an <literal>Array</literal> of the elements at the indices covered by the given <literal>Range</literal>. Alternatively, <literal>#values_at</literal> accepts any combination of <literal>Integer</literal> and <literal>Range</literal> arguments, returning the elements at any of the given indices.</para>
<example xml:id="ex.array-aref">
<title>Looking-up slices of an <literal>Array</literal></title>
<programlisting><xi:include href="examples/array-aref.rb" parse="text"/></programlisting>
</example>
<para>The element at index <literal>0</literal> can be retrieved with <literal>#[0]</literal> or <literal>#first</literal>. If <literal>#first</literal> is given an <literal>Integer</literal> argument, <replaceable>n</replaceable>, it is equivalent to <literal>#[0...<replaceable>n</replaceable>]</literal>: it returns the first <replaceable>n</replaceable> elements as an <literal>Array</literal>. Conversely, <literal>#last</literal> is equivalent to <literal>#[-1]</literal>, and <literal>#last(<replaceable>n</replaceable>)</literal> means <literal>#[-<replaceable>n</replaceable>..-1]</literal>.</para>
<example xml:id="ex.array-first-last">
<title>Looking-up the first and last elements of an <literal>Array</literal></title>
<programlisting><xi:include href="examples/array-first-last.rb" parse="text"/></programlisting>
</example>
<para>Lastly, <literal>#sample(<replaceable>n</replaceable>)</literal> returns <replaceable>n</replaceable> random elements, where <replaceable>n</replaceable> is capped at the size of the receiver. If <replaceable>n</replaceable> is omitted, it defaults to <literal>1</literal>. <remark>TODO: Describe the `random:` argument as a 1.9.3 feature</remark></para>
<example xml:id="ex.array-sample">
<title>Looking-up “random” elements of an <literal>Array</literal></title>
<programlisting><xi:include href="examples/array-sample.rb" parse="text"/></programlisting>
</example>
</sect1>
<sect1 xml:id="arr.insertion">
<title>Insertion</title>
<para><literal>#insert(<replaceable>i</replaceable>, <replaceable>o</replaceable><subscript>0</subscript>,…,<replaceable>o</replaceable><subscript><replaceable>n</replaceable></subscript>)</literal> inserts objects 0…<replaceable>n</replaceable> before the element with index <replaceable>i</replaceable> if <replaceable>i</replaceable> is positive. If <replaceable>i</replaceable> is negative, it counts from the end of the <literal>Array</literal>, and the objects are inserted after it.</para>
<example xml:id="ex.array-insert">
<title>Inserting elements into an <literal>Array</literal></title>
<programlisting><xi:include href="examples/array-insert.rb" parse="text"/></programlisting>
</example>
<para><literal>#push(<replaceable>o</replaceable>)</literal> and <literal>#<< <replaceable>o</replaceable></literal> are equivalent to <literal>#insert(-1, <replaceable>o</replaceable>)</literal>, while <literal>#unshift(<replaceable>o</replaceable>)</literal> is equivalent to <literal>#insert(0, <replaceable>o</replaceable>)</literal>.</para>
<remark>TODO: Xref #pop and #shift?</remark>
<example xml:id="ex.array-push-unshift">
<title>Appending and prepending elements to an <literal>Array</literal></title>
<programlisting><xi:include href="examples/array-push-unshift.rb" parse="text"/></programlisting>
</example>
</sect1>
<sect1 xml:id="arr.replace">
<title>Replacement</title>
<para>To replace the object at index <replaceable>n</replaceable> with <replaceable>o</replaceable>, use <literal>#[<replaceable>n</replaceable>]</literal> as an lvalue, e.g. <literal>#[<replaceable>n</replaceable>] = <replaceable>o</replaceable></literal>. If <literal>#[]=</literal> is given a pair of <literal>Integer</literal>s or a <literal>Range</literal> for its arguments, the affected slice is replaced by the rvalue.</para>
<example xml:id="ex.array-aref-set">
<title>Replacing elements of an <literal>Array</literal></title>
<programlisting><xi:include href="examples/array-aref-set.rb" parse="text"/></programlisting>
</example>
<para><literal>#fill</literal> replaces one sequence of elements with another. <literal>#fill(<replaceable>o</replaceable>)</literal> substitutes every element of the receiver for <replaceable>o</replaceable>. <literal>#fill(<replaceable>o</replaceable>, <replaceable>start</replaceable>, <replaceable>length</replaceable>)</literal> replaces index <replaceable>start</replaceable> through to index <replaceable>length</replaceable> with <replaceable>o</replaceable>. If <replaceable>length</replaceable> is omitted, it is assumed to be the length of the receiver. <literal>#fill(<replaceable>o</replaceable>, <replaceable>range</replaceable>)</literal> replaces the elements whose indices are covered by the <literal>Range</literal> <replaceable>range</replaceable> with <replaceable>o</replaceable>. If the <replaceable>o</replaceable> argument is omitted, and a block supplied instead, the selected elements are replaced with the value of the block when passed their index.</para>
<example xml:id="ex.array-fill">
<title>Replacing slices of an <literal>Array</literal></title>
<programlisting><xi:include href="examples/array-fill.rb" parse="text"/></programlisting>
</example>
</sect1>
<sect1 xml:id="arr.concat">
<title>Concatenation</title>
<para><literal>#concat(<replaceable>a</replaceable>)</literal> and its alias, <literal>#+ <replaceable>a</replaceable></literal>, append the elements of <literal>Array</literal> to the receiver.</para>
<para><literal>#join</literal> concatenates the elements of the receiver with <literal>$,</literal>—the output record separator, which is <literal>nil</literal> by default—to produce a <literal>String</literal>. If given a <literal>String</literal> argument, that is used in place of <literal>$,</literal></para>
<para><literal>#* <replaceable>string</replaceable></literal> is equivalent to <literal>#join(<replaceable>string</replaceable>)</literal>. <literal>#* <replaceable>integer</replaceable></literal> is equivalent to concatenating <replaceable>integer</replaceable> copies of the receiver.</para>
<example xml:id="ex.array-concat">
<title>Concatenating <literal>Array</literal>s and their elements</title>
<programlisting><xi:include href="examples/array-concat.rb" parse="text"/></programlisting>
</example>
</sect1>
<sect1 xml:id="arr.deletion">
<title>Deletion</title>
<para><literal>#delete_at(<replaceable>n</replaceable>)</literal> deletes and returns the element at index <replaceable>n</replaceable>. As special cases, <literal>#shift</literal> is equivalent to <literal>#delete_at(0)</literal>, and <literal>#pop</literal> is equivalent to <literal>#delete_at(-1)</literal>.</para>
<example xml:id="ex.array-delete-at">
<title>Deleting an <literal>Array</literal> element at a specific index</title>
<programlisting><xi:include href="examples/array-delete-at.rb" parse="text"/></programlisting>
</example>
<para><literal>#delete(<replaceable>e</replaceable>)</literal> deletes all elements equal to <replaceable>e</replaceable>. If no deletions occurred, <literal>nil</literal> is returned. If a block is supplied, its value is returned in place of <literal>nil</literal>.</para>
<example xml:id="ex.array-delete">
<title>Deleting <literal>Array</literal> elements</title>
<programlisting><xi:include href="examples/array-delete.rb" parse="text"/></programlisting>
</example>
<para><literal>#delete_if</literal> passes each element in turn to the associated block, deleting those for which the block evaluates to <literal>true</literal>. Its inverse is <literal>#keep_if</literal>, which deletes elements for which the block evaluates to <literal>false</literal>. <literal>#reject!</literal> and <literal>#select!</literal> behave like <literal>#delete_if!</literal> and <literal>#keep_if!</literal>, respectively, except they return the receiver if they made changes; <literal>nil</literal> otherwise.</para>
<example xml:id="ex.array-delete-if">
<title>Deleting <literal>Array</literal> elements using a block</title>
<programlisting><xi:include href="examples/array-delete-if.rb" parse="text"/></programlisting>
</example>
<para><literal>#compact!</literal> deletes all <literal>nil</literal> elements, while <literal>#uniq!</literal> deletes all duplicates. Both methods have non-bang variants which return a copy of their receiver with the elements removed.</para>
<example xml:id="ex.array-compact-uniq">
<title>Deleting <literal>nil</literal> and duplicate elements from an <literal>Array</literal></title>
<programlisting><xi:include href="examples/array-compact-uniq.rb" parse="text"/></programlisting>
</example>
<para>To remove every element from an <literal>Array</literal>, <literal>#clear</literal> can be used.</para>
<example xml:id="ex.array-clear">
<title>Deleting all elements from an <literal>Array</literal></title>
<programlisting><xi:include href="examples/array-clear.rb" parse="text"/></programlisting>
</example>
</sect1>
<sect1 xml:id="arr.arrays-of-arrays">
<title><literal>Array</literal>s of <literal>Array</literal>s</title>
<remark>TODO: Discuss creation?</remark>
<para>An <firstterm><literal>Array</literal> of <literal>Array</literal>s</firstterm> is an <literal>Array</literal> whose elements are <literal>Array</literal>s. <literal>#flatten</literal> replaces every element that is an <literal>Array</literal> with its contents, recursively. If <literal>#flatten</literal> is given an <literal>Integer</literal> argument, <replaceable>limit</replaceable>, it recurses to a maximum depth of <replaceable>limit</replaceable>. <literal>#flatten!</literal> is identical except it modifies the receiver in-place.</para>
<example xml:id="ex.array-flatten">
<title>Flattening a recursive <literal>Array</literal></title>
<programlisting><xi:include href="examples/array-flatten.rb" parse="text"/></programlisting>
</example>
<para><literal>#assoc(<replaceable>o</replaceable>)</literal> assumes the receiver is an <literal>Array</literal> of <literal>Array</literal>s, and returns the first <literal>Array</literal> whose first element is equal to <replaceable>o</replaceable>. <literal>#rassoc(<replaceable>o</replaceable>)</literal> does likewise, except it compares the second element of each <literal>Array</literal> with <replaceable>o</replaceable>. In both cases, <literal>nil</literal> is returned when no matching <literal>Array</literal> was found.</para>
<example xml:id="ex.array-assoc">
<title>Querying an associative <literal>Array</literal></title>
<programlisting><xi:include href="examples/array-assoc.rb" parse="text"/></programlisting>
</example>
<para>Assuming the receiver is an <literal>Array</literal> of <literal>Array</literal>s, where each row has the same number of columns, <literal>#transpose</literal> returns the result of transposing the rows and columns.</para>
<example xml:id="ex.array-transpose">
<title>Transposing the rows and columns of a recursive <literal>Array</literal></title>
<programlisting><xi:include href="examples/array-transpose.rb" parse="text"/></programlisting>
</example>
</sect1>
<sect1 xml:id="arr.permutations">
<title>Permutations & Combinations</title>
<para><literal>#permutation(<replaceable>size</replaceable>)</literal> yields each permutation of the receiver of length <replaceable>size</replaceable>. If <replaceable>size</replaceable> is omitted, it is assumed to be that of the receiver. Similarly, <function>Array#combination</function> yields combinations of elements with the given length.</para>
<example xml:id="ex.array-permutation-combination">
<title>Generating permutations or combinations of an <literal>Array</literal></title>
<programlisting><xi:include href="examples/array-permutation-combination.rb" parse="text"/></programlisting>
</example>
<para><literal>#product</literal> accepts any number of <literal>Array</literal> arguments, then returns an <literal>Array</literal> of <literal>Array</literal>s comprising all combinations of picking an element from the receiver and each argument. If <literal>#product</literal> is given <replaceable>n</replaceable> arguments, each element of the <literal>Array</literal> it returns has <literal><replaceable>n</replaceable> + 1</literal> elements.</para>
<example xml:id="ex.array-product">
<title>Products of an <literal>Array</literal>’s elements</title>
<programlisting><xi:include href="examples/array-product.rb" parse="text"/></programlisting>
</example>
</sect1>
<sect1 xml:id="arr.iterate">
<title>Iteration</title>
<para><literal>#each</literal> yields each element of the receiver in turn to the associated block. <literal>#each_with_index</literal> yields each element along with its index.</para>
<example xml:id="ex.array-iteration">
<title>Iterating an <literal>Array</literal></title>
<programlisting><xi:include href="examples/array-iteration.rb" parse="text"/></programlisting>
</example>
</sect1>
<sect1 xml:id="arr.set">
<title>Set Operations</title>
<para>Set operations find the difference, intersection, and union of the receiver and another <literal>Array</literal>, <replaceable>a</replaceable>. <function>Array#-(<replaceable>a</replaceable>)</function> returns the difference between the receiver and <replaceable>a</replaceable>, i.e., the elements of the receiver less the elements of <replaceable>a</replaceable>. <function>Array#&(<replaceable>a</replaceable>)</function> returns the intersection of the receiver and <replaceable>a</replaceable>, i.e., elements common to both, without duplicates. <function>Array#|(<replaceable>a</replaceable>)</function> returns the union of the receiver and <replaceable>a</replaceable>, i.e. their concatenation, minus any duplicates.</para>
<example xml:id="ex.array-set">
<title>Performing set operations on <literal>Array</literal>s</title>
<programlisting><xi:include href="examples/array-set.rb" parse="text"/></programlisting>
</example>
</sect1>
<sect1 xml:id="arr.order">
<title>Ordering</title>
<para>An <literal>Array</literal> is sorted with either <function>Array#sort</function> or <function>Array#sort_by</function>, both of which behave like their namesakes in the <literal>Enumerable</literal> module. The elements in an <literal>Array</literal> can be reversed with <function>Array#reverse</function>, or sorted in a pseudo-random order with <function>Array#shuffle</function>. All four methods order a copy of the receiver, which they return.</para>
<example xml:id="ex.array-order">
<title>Sorting the elements of an <literal>Array</literal></title>
<programlisting><xi:include href="examples/array-order.rb" parse="text"/></programlisting>
</example>
</sect1>
</chapter>