OLD | NEW |
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 utilslib; | 5 part of utilslib; |
6 | 6 |
7 typedef num NumericValueSelector<T>(T value); | 7 typedef num NumericValueSelector<T>(T value); |
8 | 8 |
9 /** | 9 /** |
10 * General purpose collection utilities. | 10 * General purpose collection utilities. |
(...skipping 22 matching lines...) Expand all Loading... |
33 // TODO(jmesserly): we won't need to do this once List | 33 // TODO(jmesserly): we won't need to do this once List |
34 // implements insertAt | 34 // implements insertAt |
35 if (arr is ObservableList) { | 35 if (arr is ObservableList) { |
36 // TODO(jmesserly): shouldn't need to cast after testing instanceof | 36 // TODO(jmesserly): shouldn't need to cast after testing instanceof |
37 ObservableList obs = arr; | 37 ObservableList obs = arr; |
38 obs.recordListInsert(pos, value); | 38 obs.recordListInsert(pos, value); |
39 } | 39 } |
40 } | 40 } |
41 } | 41 } |
42 | 42 |
43 // Collection<T> supports most of the ES 5 list methods, but it's missing | |
44 // map. | |
45 | |
46 // TODO(jmesserly): we might want a version of this that return an iterable, | |
47 // however JS, Python and Ruby versions are all eager. | |
48 static List map(Iterable source, var mapper) { | |
49 // TODO(jmesserly): I was trying to set the capacity here, but instead it | |
50 // seems to create a fixed list. Hence assigning by index below. | |
51 List result = new List(source is List ? (source as List).length : null); | |
52 int i = 0; | |
53 for (final item in source) { | |
54 result[i++] = mapper(item); | |
55 } | |
56 return result; | |
57 } | |
58 | |
59 /** | 43 /** |
60 * Finds the item in [source] that matches [test]. Returns null if | 44 * Finds the item in [source] that matches [test]. Returns null if |
61 * no item matches. The typing should be: | 45 * no item matches. The typing should be: |
62 * T find(Iterable<T> source, bool test(T item)), but we don't have generic | 46 * T find(Iterable<T> source, bool test(T item)), but we don't have generic |
63 * functions. | 47 * functions. |
64 */ | 48 */ |
65 static find(Iterable source, bool test(item)) { | 49 static find(Iterable source, bool test(item)) { |
66 for (final item in source) { | 50 for (final item in source) { |
67 if (test(item)) return item; | 51 if (test(item)) return item; |
68 } | 52 } |
69 | 53 |
70 return null; | 54 return null; |
71 } | 55 } |
72 | 56 |
73 /** Compute the minimum of an iterable. Returns null if empty. */ | 57 /** Compute the minimum of an iterable. Returns null if empty. */ |
74 static num min(Iterable source) { | 58 static num min(Iterable source) { |
75 final iter = source.iterator(); | 59 final iter = source.iterator; |
76 if (!iter.hasNext) { | 60 if (!iter.moveNext()) { |
77 return null; | 61 return null; |
78 } | 62 } |
79 num best = iter.next(); | 63 num best = iter.current; |
80 while (iter.hasNext) { | 64 while (iter.moveNext()) { |
81 best = Math.min(best, iter.next()); | 65 best = Math.min(best, iter.current); |
82 } | 66 } |
83 return best; | 67 return best; |
84 } | 68 } |
85 | 69 |
86 /** Compute the maximum of an iterable. Returns null if empty. */ | 70 /** Compute the maximum of an iterable. Returns null if empty. */ |
87 static num max(Iterable source) { | 71 static num max(Iterable source) { |
88 final iter = source.iterator(); | 72 final iter = source.iterator; |
89 if (!iter.hasNext) { | 73 if (!iter.moveNext()) { |
90 return null; | 74 return null; |
91 } | 75 } |
92 num best = iter.next(); | 76 num best = iter.current; |
93 while (iter.hasNext) { | 77 while (iter.moveNext()) { |
94 best = Math.max(best, iter.next()); | 78 best = Math.max(best, iter.current); |
95 } | 79 } |
96 return best; | 80 return best; |
97 } | 81 } |
98 | 82 |
99 /** Orders an iterable by its values, or by a key selector. */ | 83 /** Orders an iterable by its values, or by a key selector. */ |
100 static List orderBy(Iterable source, [NumericValueSelector selector = null]) { | 84 static List orderBy(Iterable source, [NumericValueSelector selector = null]) { |
101 final result = new List.from(source); | 85 final result = new List.from(source); |
102 sortBy(result, selector); | 86 sortBy(result, selector); |
103 return result; | 87 return result; |
104 } | 88 } |
105 | 89 |
106 /** Sorts a list by its values, or by a key selector. */ | 90 /** Sorts a list by its values, or by a key selector. */ |
107 // TODO(jmesserly): we probably don't want to call the key selector more than | 91 // TODO(jmesserly): we probably don't want to call the key selector more than |
108 // once for a given element. This would improve performance and the API | 92 // once for a given element. This would improve performance and the API |
109 // contract could be stronger. | 93 // contract could be stronger. |
110 static void sortBy(List list, [NumericValueSelector selector = null]) { | 94 static void sortBy(List list, [NumericValueSelector selector = null]) { |
111 if (selector != null) { | 95 if (selector != null) { |
112 list.sort((x, y) => selector(x) - selector(y)); | 96 list.sort((x, y) => selector(x) - selector(y)); |
113 } else { | 97 } else { |
114 list.sort((x, y) => x - y); | 98 list.sort((x, y) => x - y); |
115 } | 99 } |
116 } | 100 } |
117 | 101 |
118 /** Compute the sum of an iterable. An empty iterable is an error. */ | 102 /** Compute the sum of an iterable. An empty iterable is an error. */ |
119 static num sum(Iterable source, [NumericValueSelector selector = null]) { | 103 static num sum(Iterable source, [NumericValueSelector selector = null]) { |
120 final iter = source.iterator(); | 104 final iter = source.iterator; |
| 105 bool wasEmpty = true; |
121 num total = 0; | 106 num total = 0; |
122 if (selector != null) { | 107 if (selector != null) { |
123 do { | 108 for (var element in source) { |
124 total += selector(iter.next()); | 109 wasEmpty = false; |
125 } while (iter.hasNext); | 110 total += selector(element); |
| 111 } |
126 } else { | 112 } else { |
127 do { | 113 for (num element in source) { |
128 total += iter.next(); | 114 wasEmpty = false; |
129 } while (iter.hasNext); | 115 total += element; |
| 116 } |
130 } | 117 } |
| 118 if (wasEmpty) throw new StateError("No elements"); |
131 return total; | 119 return total; |
132 } | 120 } |
133 | 121 |
134 // TODO(jmesserly): something like should exist on Map, either a method or a | 122 // TODO(jmesserly): something like should exist on Map, either a method or a |
135 // constructor, see bug #5340679 | 123 // constructor, see bug #5340679 |
136 static void copyMap(Map dest, Map source) { | 124 static void copyMap(Map dest, Map source) { |
137 for (final k in source.keys) { | 125 for (final k in source.keys) { |
138 dest[k] = source[k]; | 126 dest[k] = source[k]; |
139 } | 127 } |
140 } | 128 } |
141 } | 129 } |
OLD | NEW |