Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(122)

Side by Side Diff: sdk/lib/core/iterable.dart

Issue 11783009: Big merge from experimental to bleeding edge. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sdk/lib/core/int.dart ('k') | sdk/lib/core/iterator.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of dart.core; 5 part of dart.core;
6 6
7 /** 7 /**
8 * The [Iterable] interface allows to get an [Iterator] out of an 8 * The [Iterable] interface allows to get an [Iterator] out of an
9 * [Iterable] object. 9 * [Iterable] object.
10 * 10 *
11 * This interface is used by the for-in construct to iterate over an 11 * This interface is used by the for-in construct to iterate over an
12 * [Iterable] object. 12 * [Iterable] object.
13 * The for-in construct takes an [Iterable] object at the right-hand 13 * The for-in construct takes an [Iterable] object at the right-hand
14 * side, and calls its [iterator] method to get an [Iterator] on it. 14 * side, and calls its [iterator] method to get an [Iterator] on it.
15 * 15 *
16 * A user-defined class that implements the [Iterable] interface can 16 * A user-defined class that implements the [Iterable] interface can
17 * be used as the right-hand side of a for-in construct. 17 * be used as the right-hand side of a for-in construct.
18 */ 18 */
19 abstract class Iterable<E> { 19 abstract class Iterable<E> {
20 const Iterable();
21
20 /** 22 /**
21 * Returns an [Iterator] that iterates over this [Iterable] object. 23 * Returns an [Iterator] that iterates over this [Iterable] object.
22 */ 24 */
23 Iterator<E> iterator(); 25 Iterator<E> get iterator;
24 } 26
27 /**
28 * Returns a lazy [Iterable] where each element [:e:] of [this] is replaced
29 * by the result of [:f(e):].
30 *
31 * This method returns a view of the mapped elements. As long as the
32 * returned [Iterable] is not iterated over, the supplied function [f] will
33 * not be invoked. The transformed elements will not be cached. Iterating
34 * multiple times over the the returned [Iterable] will invoke the supplied
35 * function [f] multiple times on the same element.
36 */
37 Iterable mappedBy(f(E element)) => new MappedIterable<E, dynamic>(this, f);
38
39 /**
40 * Returns a lazy [Iterable] with all elements that satisfy the
41 * predicate [f].
42 *
43 * This method returns a view of the mapped elements. As long as the
44 * returned [Iterable] is not iterated over, the supplied function [f] will
45 * not be invoked. Iterating will not cache results, and thus iterating
46 * multiple times over the the returned [Iterable] will invoke the supplied
47 * function [f] multiple times on the same element.
48 */
49 Iterable<E> where(bool f(E element)) => new WhereIterable<E>(this, f);
50
51 /**
52 * Check whether the collection contains an element equal to [element].
53 */
54 bool contains(E element) {
55 for (E e in this) {
56 if (e == element) return true;
57 }
58 return false;
59 }
60
61 /**
62 * Applies the function [f] to each element of this collection.
63 */
64 void forEach(void f(E element)) {
65 for (E element in this) f(element);
66 }
67
68 /**
69 * Reduce a collection to a single value by iteratively combining each element
70 * of the collection with an existing value using the provided function.
71 * Use [initialValue] as the initial value, and the function [combine] to
72 * create a new value from the previous one and an element.
73 *
74 * Example of calculating the sum of a collection:
75 *
76 * collection.reduce(0, (prev, element) => prev + element);
77 */
78 dynamic reduce(var initialValue,
79 dynamic combine(var previousValue, E element)) {
80 var value = initialValue;
81 for (E element in this) value = combine(value, element);
82 return value;
83 }
84
85 /**
86 * Returns true if every elements of this collection satisify the
87 * predicate [f]. Returns false otherwise.
88 */
89 bool every(bool f(E element)) {
90 for (E element in this) {
91 if (!f(element)) return false;
92 }
93 return true;
94 }
95
96 /**
97 * Convert each element to a [String] and concatenate the strings.
98 *
99 * Converts each element to a [String] by calling [Object.toString] on it.
100 * Then concatenates the strings, optionally separated by the [separator]
101 * string.
102 */
103 String join([String separator]) {
104 Iterator<E> iterator = this.iterator;
105 if (!iterator.moveNext()) return "";
106 StringBuffer buffer = new StringBuffer();
107 if (separator == null || separator == "") {
108 do {
109 buffer.add("${iterator.current}");
110 } while (iterator.moveNext());
111 } else {
112 buffer.add("${iterator.current}");
113 while (iterator.moveNext()) {
114 buffer.add(separator);
115 buffer.add("${iterator.current}");
116 }
117 }
118 return buffer.toString();
119 }
120
121 /**
122 * Returns true if one element of this collection satisfies the
123 * predicate [f]. Returns false otherwise.
124 */
125 bool any(bool f(E element)) {
126 for (E element in this) {
127 if (f(element)) return true;
128 }
129 return false;
130 }
131
132 List<E> toList() => new List<E>.from(this);
133 Set<E> toSet() => new Set<E>.from(this);
134
135 /**
136 * Returns the number of elements in [this].
137 *
138 * Counting all elements may be involve running through all elements and can
139 * therefore be slow.
140 */
141 int get length {
142 int count = 0;
143 Iterator it = iterator;
144 while (it.moveNext()) {
145 count++;
146 }
147 return count;
148 }
149
150 /**
151 * Find the least element in the iterable.
152 *
153 * Returns null if the iterable is empty.
154 * Otherwise returns an element [:x:] of this [Iterable] so that
155 * [:x:] is not greater than [:y:] (that is, [:compare(x, y) <= 0:]) for all
156 * other elements [:y:] in the iterable.
157 *
158 * The [compare] function must be a proper [Comparator<T>]. If a function is
159 * not provided, [compare] defaults to [Comparable.compare].
160 */
161 E min([int compare(E a, E b)]) {
162 if (compare == null) compare = Comparable.compare;
163 Iterator it = iterator;
164 if (!it.moveNext()) return null;
165 E min = it.current;
166 while (it.moveNext()) {
167 E current = it.current;
168 if (compare(min, current) > 0) min = current;
169 }
170 return min;
171 }
172
173 /**
174 * Find the largest element in the iterable.
175 *
176 * Returns null if the iterable is empty.
177 * Otherwise returns an element [:x:] of this [Iterable] so that
178 * [:x:] is not smaller than [:y:] (that is, [:compare(x, y) >= 0:]) for all
179 * other elements [:y:] in the iterable.
180 *
181 * The [compare] function must be a proper [Comparator<T>]. If a function is
182 * not provided, [compare] defaults to [Comparable.compare].
183 */
184 E max([int compare(E a, E b)]) {
185 if (compare == null) compare = Comparable.compare;
186 Iterator it = iterator;
187 if (!it.moveNext()) return null;
188 E max = it.current;
189 while (it.moveNext()) {
190 E current = it.current;
191 if (compare(max, current) < 0) max = current;
192 }
193 return max;
194 }
195
196 /**
197 * Returns true if there is no element in this collection.
198 */
199 bool get isEmpty => !iterator.moveNext();
200
201 /**
202 * Returns an [Iterable] with at most [n] elements.
203 *
204 * The returned [Iterable] may contain fewer than [n] elements, if [this]
205 * contains fewer than [n] elements.
206 */
207 Iterable<E> take(int n) {
208 return new TakeIterable<E>(this, n);
209 }
210
211 /**
212 * Returns an [Iterable] that stops once [test] is not satisfied anymore.
213 *
214 * The filtering happens lazily. Every new [Iterator] of the returned
215 * [Iterable] will start iterating over the elements of [this].
216 * When the iterator encounters an element [:e:] that does not satisfy [test],
217 * it discards [:e:] and moves into the finished state. That is, it will not
218 * ask or provide any more elements.
219 */
220 Iterable<E> takeWhile(bool test(E value)) {
221 return new TakeWhileIterable<E>(this, test);
222 }
223
224 /**
225 * Returns an [Iterable] that skips the first [n] elements.
226 *
227 * If [this] has fewer than [n] elements, then the resulting [Iterable] will
228 * be empty.
229 */
230 Iterable<E> skip(int n) {
231 return new SkipIterable<E>(this, n);
232 }
233
234 /**
235 * Returns an [Iterable] that skips elements while [test] is satisfied.
236 *
237 * The filtering happens lazily. Every new [Iterator] of the returned
238 * [Iterable] will iterate over all elements of [this].
239 * As long as the iterator's elements do not satisfy [test] they are
240 * discarded. Once an element satisfies the [test] the iterator stops testing
241 * and uses every element unconditionally.
242 */
243 Iterable<E> skipWhile(bool test(E value)) {
244 return new SkipWhileIterable<E>(this, test);
245 }
246
247 /**
248 * Returns the first element.
249 *
250 * If [this] is empty throws a [StateError]. Otherwise this method is
251 * equivalent to [:this.elementAt(0):]
252 */
253 E get first {
254 Iterator it = iterator;
255 if (!it.moveNext()) {
256 throw new StateError("No elements");
257 }
258 return it.current;
259 }
260
261 /**
262 * Returns the last element.
263 *
264 * If [this] is empty throws a [StateError].
265 */
266 E get last {
267 Iterator it = iterator;
268 if (!it.moveNext()) {
269 throw new StateError("No elements");
270 }
271 E result;
272 do {
273 result = it.current;
274 } while(it.moveNext());
275 return result;
276 }
277
278 /**
279 * Returns the single element in [this].
280 *
281 * If [this] is empty or has more than one element throws a [StateError].
282 */
283 E get single {
284 Iterator it = iterator;
285 if (!it.moveNext()) throw new StateError("No elements");
286 E result = it.current;
287 if (it.moveNext()) throw new StateError("More than one element");
288 return result;
289 }
290
291 /**
292 * Returns the first element that satisfies the given predicate [f].
293 *
294 * If none matches, the result of invoking the [orElse] function is
295 * returned. By default, when [orElse] is `null`, a [StateError] is
296 * thrown.
297 */
298 E firstMatching(bool test(E value), { E orElse() }) {
299 // TODO(floitsch): check that arguments are of correct type?
300 for (E element in this) {
301 if (test(element)) return element;
302 }
303 if (orElse != null) return orElse();
304 throw new StateError("No matching element");
305 }
306
307 /**
308 * Returns the last element that satisfies the given predicate [f].
309 *
310 * If none matches, the result of invoking the [orElse] function is
311 * returned. By default, when [orElse] is [:null:], a [StateError] is
312 * thrown.
313 */
314 E lastMatching(bool test(E value), {E orElse()}) {
315 // TODO(floitsch): check that arguments are of correct type?
316 E result = null;
317 bool foundMatching = false;
318 for (E element in this) {
319 if (test(element)) {
320 result = element;
321 foundMatching = true;
322 }
323 }
324 if (foundMatching) return result;
325 if (orElse != null) return orElse();
326 throw new StateError("No matching element");
327 }
328
329 /**
330 * Returns the single element that satisfies [f]. If no or more than one
331 * element match then a [StateError] is thrown.
332 */
333 E singleMatching(bool test(E value)) {
334 // TODO(floitsch): check that argument is of correct type?
335 E result = null;
336 bool foundMatching = false;
337 for (E element in this) {
338 if (test(element)) {
339 if (foundMatching) {
340 throw new StateError("More than one matching element");
341 }
342 result = element;
343 foundMatching = true;
344 }
345 }
346 if (foundMatching) return result;
347 throw new StateError("No matching element");
348 }
349
350 /**
351 * Returns the [index]th element.
352 *
353 * If [this] [Iterable] has fewer than [index] elements throws a
354 * [RangeError].
355 *
356 * Note: if [this] does not have a deterministic iteration order then the
357 * function may simply return any element without any iteration if there are
358 * at least [index] elements in [this].
359 */
360 E elementAt(int index) {
361 if (index is! int || index < 0) throw new RangeError.value(index);
362 int remaining = index;
363 for (E element in this) {
364 if (remaining == 0) return element;
365 remaining--;
366 }
367 throw new RangeError.value(index);
368 }
369 }
370
371 typedef T _Transformation<S, T>(S value);
372
373 class MappedIterable<S, T> extends Iterable<T> {
374 final Iterable<S> _iterable;
375 final _Transformation _f;
376
377 MappedIterable(this._iterable, T this._f(S element));
378
379 Iterator<T> get iterator => new MappedIterator<S, T>(_iterable.iterator, _f);
380
381 // Length related functions are independent of the mapping.
382 int get length => _iterable.length;
383 bool get isEmpty => _iterable.isEmpty;
384 }
385
386 class MappedIterator<S, T> extends Iterator<T> {
387 T _current;
388 final Iterator<S> _iterator;
389 final _Transformation _f;
390
391 MappedIterator(this._iterator, T this._f(S element));
392
393 bool moveNext() {
394 if (_iterator.moveNext()) {
395 _current = _f(_iterator.current);
396 return true;
397 } else {
398 _current = null;
399 return false;
400 }
401 }
402
403 T get current => _current;
404 }
405
406 typedef bool _ElementPredicate<E>(E element);
407
408 class WhereIterable<E> extends Iterable<E> {
409 final Iterable<E> _iterable;
410 final _ElementPredicate _f;
411
412 WhereIterable(this._iterable, bool this._f(E element));
413
414 Iterator<E> get iterator => new WhereIterator<E>(_iterable.iterator, _f);
415 }
416
417 class WhereIterator<E> extends Iterator<E> {
418 final Iterator<E> _iterator;
419 final _ElementPredicate _f;
420
421 WhereIterator(this._iterator, bool this._f(E element));
422
423 bool moveNext() {
424 while (_iterator.moveNext()) {
425 if (_f(_iterator.current)) {
426 return true;
427 }
428 }
429 return false;
430 }
431
432 E get current => _iterator.current;
433 }
434
435 class TakeIterable<E> extends Iterable<E> {
436 final Iterable<E> _iterable;
437 final int _takeCount;
438
439 TakeIterable(this._iterable, this._takeCount) {
440 if (_takeCount is! int || _takeCount < 0) {
441 throw new ArgumentError(_takeCount);
442 }
443 }
444
445 Iterator<E> get iterator {
446 return new TakeIterator<E>(_iterable.iterator, _takeCount);
447 }
448 }
449
450 class TakeIterator<E> extends Iterator<E> {
451 final Iterator<E> _iterator;
452 int _remaining;
453
454 TakeIterator(this._iterator, this._remaining) {
455 assert(_remaining is int && _remaining >= 0);
456 }
457
458 bool moveNext() {
459 _remaining--;
460 if (_remaining >= 0) {
461 return _iterator.moveNext();
462 }
463 _remaining = -1;
464 return false;
465 }
466
467 E get current {
468 if (_remaining < 0) return null;
469 return _iterator.current;
470 }
471 }
472
473 class TakeWhileIterable<E> extends Iterable<E> {
474 final Iterable<E> _iterable;
475 final _ElementPredicate _f;
476
477 TakeWhileIterable(this._iterable, bool this._f(E element));
478
479 Iterator<E> get iterator {
480 return new TakeWhileIterator<E>(_iterable.iterator, _f);
481 }
482 }
483
484 class TakeWhileIterator<E> extends Iterator<E> {
485 final Iterator<E> _iterator;
486 final _ElementPredicate _f;
487 bool _isFinished = false;
488
489 TakeWhileIterator(this._iterator, bool this._f(E element));
490
491 bool moveNext() {
492 if (_isFinished) return false;
493 if (!_iterator.moveNext() || !_f(_iterator.current)) {
494 _isFinished = true;
495 return false;
496 }
497 return true;
498 }
499
500 E get current {
501 if (_isFinished) return null;
502 return _iterator.current;
503 }
504 }
505
506 class SkipIterable<E> extends Iterable<E> {
507 final Iterable<E> _iterable;
508 final int _skipCount;
509
510 SkipIterable(this._iterable, this._skipCount) {
511 if (_skipCount is! int || _skipCount < 0) {
512 throw new ArgumentError(_skipCount);
513 }
514 }
515
516 Iterable<E> skip(int n) {
517 if (n is! int || n < 0) {
518 throw new ArgumentError(n);
519 }
520 return new SkipIterable<E>(_iterable, _skipCount + n);
521 }
522
523 Iterator<E> get iterator {
524 return new SkipIterator<E>(_iterable.iterator, _skipCount);
525 }
526 }
527
528 class SkipIterator<E> extends Iterator<E> {
529 final Iterator<E> _iterator;
530 int _skipCount;
531
532 SkipIterator(this._iterator, this._skipCount) {
533 assert(_skipCount is int && _skipCount >= 0);
534 }
535
536 bool moveNext() {
537 for (int i = 0; i < _skipCount; i++) _iterator.moveNext();
538 _skipCount = 0;
539 return _iterator.moveNext();
540 }
541
542 E get current => _iterator.current;
543 }
544
545 class SkipWhileIterable<E> extends Iterable<E> {
546 final Iterable<E> _iterable;
547 final _ElementPredicate _f;
548
549 SkipWhileIterable(this._iterable, bool this._f(E element));
550
551 Iterator<E> get iterator {
552 return new SkipWhileIterator<E>(_iterable.iterator, _f);
553 }
554 }
555
556 class SkipWhileIterator<E> extends Iterator<E> {
557 final Iterator<E> _iterator;
558 final _ElementPredicate _f;
559 bool _hasSkipped = false;
560
561 SkipWhileIterator(this._iterator, bool this._f(E element));
562
563 bool moveNext() {
564 if (!_hasSkipped) {
565 _hasSkipped = true;
566 while (_iterator.moveNext()) {
567 if (!_f(_iterator.current)) return true;
568 }
569 }
570 return _iterator.moveNext();
571 }
572
573 E get current => _iterator.current;
574 }
OLDNEW
« no previous file with comments | « sdk/lib/core/int.dart ('k') | sdk/lib/core/iterator.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698