|
1 /* |
|
2 Copyright (c) 2009, Yahoo! Inc. All rights reserved. |
|
3 Code licensed under the BSD License: |
|
4 http://developer.yahoo.net/yui/license.txt |
|
5 version: 3.0.0 |
|
6 build: 1549 |
|
7 */ |
|
8 YUI.add('collection', function(Y) { |
|
9 |
|
10 /** |
|
11 * Collection utilities beyond what is provided in the YUI core |
|
12 * @module collection |
|
13 */ |
|
14 |
|
15 var L = Y.Lang, Native = Array.prototype, A = Y.Array; |
|
16 |
|
17 /** |
|
18 * Adds the following array utilities to the YUI instance |
|
19 * (Y.Array). This is in addition to the methods provided |
|
20 * in the core. |
|
21 * @class YUI~array~extras |
|
22 */ |
|
23 |
|
24 /** |
|
25 * Returns the index of the last item in the array |
|
26 * that contains the specified value, -1 if the |
|
27 * value isn't found. |
|
28 * method Array.lastIndexOf |
|
29 * @static |
|
30 * @param a {Array} the array to search |
|
31 * @param val the value to search for |
|
32 * @return {int} the index of hte item that contains the value or -1 |
|
33 */ |
|
34 A.lastIndexOf = (Native.lastIndexOf) ? |
|
35 function(a ,val) { |
|
36 return a.lastIndexOf(val); |
|
37 } : |
|
38 function(a, val) { |
|
39 for (var i=a.length-1; i>=0; i=i-1) { |
|
40 if (a[i] === val) { |
|
41 break; |
|
42 } |
|
43 } |
|
44 return i; |
|
45 }; |
|
46 |
|
47 /** |
|
48 * Returns a copy of the array with the duplicate entries removed |
|
49 * @method Array.unique |
|
50 * @static |
|
51 * @param a {Array} the array to find the subset of uniques for |
|
52 * @param sort {bool} flag to denote if the array is sorted or not. Defaults to false, the more general operation |
|
53 * @return {Array} a copy of the array with duplicate entries removed |
|
54 */ |
|
55 A.unique = function(a, sort) { |
|
56 var b = a.slice(), i = 0, n = -1, item = null; |
|
57 |
|
58 while (i < b.length) { |
|
59 item = b[i]; |
|
60 while ((n = b.lastIndexOf(item)) !== i) { |
|
61 b.splice(n, 1); |
|
62 } |
|
63 i += 1; |
|
64 } |
|
65 |
|
66 // Note: the sort option doesn't really belong here... I think it was added |
|
67 // because there was a way to fast path the two operations together. That |
|
68 // implementation was not working, so I replaced it with the following. |
|
69 // Leaving it in so that the API doesn't get broken. |
|
70 if (sort) { |
|
71 if (L.isNumber(b[0])) { |
|
72 b.sort(A.numericSort); |
|
73 } else { |
|
74 b.sort(); |
|
75 } |
|
76 } |
|
77 |
|
78 return b; |
|
79 }; |
|
80 |
|
81 /** |
|
82 * Executes the supplied function on each item in the array. |
|
83 * Returns a new array containing the items that the supplied |
|
84 * function returned true for. |
|
85 * @method Array.filter |
|
86 * @param a {Array} the array to iterate |
|
87 * @param f {Function} the function to execute on each item |
|
88 * @param o Optional context object |
|
89 * @static |
|
90 * @return {Array} The items on which the supplied function |
|
91 * returned true. If no items matched an empty array is |
|
92 * returned. |
|
93 */ |
|
94 A.filter = (Native.filter) ? |
|
95 function(a, f, o) { |
|
96 return Native.filter.call(a, f, o); |
|
97 } : |
|
98 function(a, f, o) { |
|
99 var results = []; |
|
100 A.each(a, function(item, i, a) { |
|
101 if (f.call(o, item, i, a)) { |
|
102 results.push(item); |
|
103 } |
|
104 }); |
|
105 |
|
106 return results; |
|
107 }; |
|
108 |
|
109 /** |
|
110 * The inverse of filter. Executes the supplied function on each item. |
|
111 * Returns a new array containing the items that the supplied |
|
112 * function returned *false* for. |
|
113 * @method Array.reject |
|
114 * @param a {Array} the array to iterate |
|
115 * @param f {Function} the function to execute on each item |
|
116 * @param o Optional context object |
|
117 * @static |
|
118 * @return {Array} The items on which the supplied function |
|
119 * returned false. |
|
120 */ |
|
121 A.reject = function(a, f, o) { |
|
122 return A.filter(a, function(item, i, a) { |
|
123 return !f.call(o, item, i, a); |
|
124 }); |
|
125 }; |
|
126 |
|
127 /** |
|
128 * Executes the supplied function on each item in the array. |
|
129 * @method Array.every |
|
130 * @param a {Array} the array to iterate |
|
131 * @param f {Function} the function to execute on each item |
|
132 * @param o Optional context object |
|
133 * @static |
|
134 * @return {boolean} true if every item in the array returns true |
|
135 * from the supplied function. |
|
136 */ |
|
137 A.every = (Native.every) ? |
|
138 function(a, f, o) { |
|
139 return Native.every.call(a,f,o); |
|
140 } : |
|
141 function(a, f, o) { |
|
142 var l = a.length; |
|
143 for (var i = 0; i < l; i=i+1) { |
|
144 if (!f.call(o, a[i], i, a)) { |
|
145 return false; |
|
146 } |
|
147 } |
|
148 |
|
149 return true; |
|
150 }; |
|
151 |
|
152 /** |
|
153 * Executes the supplied function on each item in the array. |
|
154 * @method Array.map |
|
155 * @param a {Array} the array to iterate |
|
156 * @param f {Function} the function to execute on each item |
|
157 * @param o Optional context object |
|
158 * @static |
|
159 * @return {Array} A new array containing the return value |
|
160 * of the supplied function for each item in the original |
|
161 * array. |
|
162 */ |
|
163 A.map = (Native.map) ? |
|
164 function(a, f, o) { |
|
165 return Native.map.call(a, f, o); |
|
166 } : |
|
167 function(a, f, o) { |
|
168 var results = []; |
|
169 A.each(a, function(item, i, a) { |
|
170 results.push(f.call(o, item, i, a)); |
|
171 }); |
|
172 return results; |
|
173 }; |
|
174 |
|
175 |
|
176 /** |
|
177 * Executes the supplied function on each item in the array. |
|
178 * Reduce "folds" the array into a single value. |
|
179 * @method Array.reduce |
|
180 * @param a {Array} the array to iterate |
|
181 * @param init The initial value to start from |
|
182 * @param f {Function} the function to execute on each item. It |
|
183 * is responsible for returning the updated value of the |
|
184 * computation. |
|
185 * @param o Optional context object |
|
186 * @static |
|
187 * @return A value that results from iteratively applying the |
|
188 * supplied function to each element in the array. |
|
189 */ |
|
190 A.reduce = (Native.reduce) ? |
|
191 function(a, init, f, o) { |
|
192 //Firefox's Array.reduce does not allow inclusion of a |
|
193 // thisObject, so we need to implement it manually |
|
194 return Native.reduce.call(a, function(init, item, i, a) { |
|
195 return f.call(o, init, item, i, a); |
|
196 }, init); |
|
197 } : |
|
198 function(a, init, f, o) { |
|
199 var r = init; |
|
200 A.each(a, function (item, i, a) { |
|
201 r = f.call(o, r, item, i, a); |
|
202 }); |
|
203 return r; |
|
204 }; |
|
205 |
|
206 |
|
207 /** |
|
208 * Executes the supplied function on each item in the array, |
|
209 * searching for the first item that matches the supplied |
|
210 * function. |
|
211 * @method Array.find |
|
212 * @param a {Array} the array to search |
|
213 * @param f {Function} the function to execute on each item. |
|
214 * Iteration is stopped as soon as this function returns true |
|
215 * on an item. |
|
216 * @param o Optional context object |
|
217 * @static |
|
218 * @return {object} the first item that the supplied function |
|
219 * returns true for, or null if it never returns true |
|
220 */ |
|
221 A.find = function(a, f, o) { |
|
222 var l = a.length; |
|
223 for(var i=0; i < l; i++) { |
|
224 if (f.call(o, a[i], i, a)) { |
|
225 return a[i]; |
|
226 } |
|
227 } |
|
228 return null; |
|
229 }; |
|
230 |
|
231 /** |
|
232 * Iterates over an array, returning a new array of all the elements |
|
233 * that match the supplied regular expression |
|
234 * @method Array.grep |
|
235 * @param a {Array} a collection to iterate over |
|
236 * @param pattern {RegExp} The regular expression to test against |
|
237 * each item |
|
238 * @static |
|
239 * @return {Array} All the items in the collection that |
|
240 * produce a match against the supplied regular expression. |
|
241 * If no items match, an empty array is returned. |
|
242 */ |
|
243 A.grep = function (a, pattern) { |
|
244 return A.filter(a, function (item, index) { |
|
245 return pattern.test(item); |
|
246 }); |
|
247 }; |
|
248 |
|
249 |
|
250 /** |
|
251 * Partitions an array into two new arrays, one with the items |
|
252 * that match the supplied function, and one with the items that |
|
253 * do not. |
|
254 * @method Array.partition |
|
255 * @param a {Array} a collection to iterate over |
|
256 * @paran f {Function} a function that will receive each item |
|
257 * in the collection and its index. |
|
258 * @param o Optional execution context of f. |
|
259 * @static |
|
260 * @return An object with two members, 'matches' and 'rejects', |
|
261 * that are arrays containing the items that were selected or |
|
262 * rejected by the test function (or an empty array). |
|
263 */ |
|
264 A.partition = function (a, f, o) { |
|
265 var results = {matches: [], rejects: []}; |
|
266 A.each(a, function (item, index) { |
|
267 var set = f.call(o, item, index, a) ? results.matches : results.rejects; |
|
268 set.push(item); |
|
269 }); |
|
270 return results; |
|
271 }; |
|
272 |
|
273 /** |
|
274 * Creates an array of arrays by pairing the corresponding |
|
275 * elements of two arrays together into a new array. |
|
276 * @method Array.zip |
|
277 * @param a {Array} a collection to iterate over |
|
278 * @param a2 {Array} another collection whose members will be |
|
279 * paired with members of the first parameter |
|
280 * @static |
|
281 * @return An array of arrays formed by pairing each element |
|
282 * of the first collection with an item in the second collection |
|
283 * having the corresponding index. |
|
284 */ |
|
285 A.zip = function (a, a2) { |
|
286 var results = []; |
|
287 A.each(a, function (item, index) { |
|
288 results.push([item, a2[index]]); |
|
289 }); |
|
290 return results; |
|
291 }; |
|
292 |
|
293 |
|
294 }, '3.0.0' ); |