OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 typedef num NumericValueSelector<T>(T value); | |
6 | |
7 /** | |
8 * General purpose collection utilities. | |
9 * TODO(jmesserly): make these top level functions? | |
10 */ | |
11 class CollectionUtils { | |
12 | |
13 static void insertAt(List arr, int pos, value) { | |
14 assert (pos >= 0); | |
15 assert (pos <= arr.length); | |
16 | |
17 if (pos == arr.length) { | |
18 arr.add(value); | |
19 } else { | |
20 // TODO(sigmund): replace this push with a call that ensures capacity | |
21 // (currently not supported in the JS implementation of list). E.g. | |
22 // [: arr.length = arr.length + 1; :] | |
23 arr.add(null); | |
24 | |
25 // shift elements from [pos] (note: arr already has null @ length - 1) | |
26 for (int i = arr.length - 2; i >= pos; i--) { | |
27 arr[i + 1] = arr[i]; | |
28 } | |
29 arr[pos] = value; | |
30 | |
31 // TODO(jmesserly): we won't need to do this once List | |
32 // implements insertAt | |
33 if (arr is ObservableList) { | |
34 // TODO(jmesserly): shouldn't need to cast after testing instanceof | |
35 ObservableList obs = arr; | |
36 obs.recordListInsert(pos, value); | |
37 } | |
38 } | |
39 } | |
40 | |
41 // Collection<T> supports most of the ES 5 list methods, but it's missing | |
42 // map. | |
43 | |
44 // TODO(jmesserly): we might want a version of this that return an iterable, | |
45 // however JS, Python and Ruby versions are all eager. | |
46 static List map(Iterable source, var mapper) { | |
47 // TODO(jmesserly): I was trying to set the capacity here, but instead it | |
48 // seems to create a fixed list. Hence assigning by index below. | |
49 List result = new List(source is List ? source.dynamic.length : null); | |
50 int i = 0; | |
51 for (final item in source) { | |
52 result[i++] = mapper(item); | |
53 } | |
54 return result; | |
55 } | |
56 | |
57 /** | |
58 * Finds the item in [source] that matches [test]. Returns null if | |
59 * no item matches. The typing should be: | |
60 * T find(Iterable<T> source, bool test(T item)), but we don't have generic | |
61 * functions. | |
62 */ | |
63 static find(Iterable source, bool test(item)) { | |
64 for (final item in source) { | |
65 if (test(item)) return item; | |
66 } | |
67 | |
68 return null; | |
69 } | |
70 | |
71 /** Compute the minimum of an iterable. Returns null if empty. */ | |
72 static num min(Iterable source) { | |
73 final iter = source.iterator(); | |
74 if (!iter.hasNext()) { | |
75 return null; | |
76 } | |
77 num best = iter.next(); | |
78 while (iter.hasNext()) { | |
79 best = Math.min(best, iter.next()); | |
80 } | |
81 return best; | |
82 } | |
83 | |
84 /** Compute the maximum of an iterable. Returns null if empty. */ | |
85 static num max(Iterable source) { | |
86 final iter = source.iterator(); | |
87 if (!iter.hasNext()) { | |
88 return null; | |
89 } | |
90 num best = iter.next(); | |
91 while (iter.hasNext()) { | |
92 best = Math.max(best, iter.next()); | |
93 } | |
94 return best; | |
95 } | |
96 | |
97 /** Orders an iterable by its values, or by a key selector. */ | |
98 static List orderBy(Iterable source, [NumericValueSelector selector = null]) { | |
99 final result = new List.from(source); | |
100 sortBy(result, selector); | |
101 return result; | |
102 } | |
103 | |
104 /** Sorts a list by its values, or by a key selector. */ | |
105 // TODO(jmesserly): we probably don't want to call the key selector more than | |
106 // once for a given element. This would improve performance and the API | |
107 // contract could be stronger. | |
108 static void sortBy(List list, [NumericValueSelector selector = null]) { | |
109 if (selector != null) { | |
110 list.sort((x, y) => selector(x) - selector(y)); | |
111 } else { | |
112 list.sort((x, y) => x - y); | |
113 } | |
114 } | |
115 | |
116 /** Compute the sum of an iterable. An empty iterable is an error. */ | |
117 static num sum(Iterable source, [NumericValueSelector selector = null]) { | |
118 final iter = source.iterator(); | |
119 num total = 0; | |
120 if (selector != null) { | |
121 do { | |
122 total += selector(iter.next()); | |
123 } while (iter.hasNext()); | |
124 } else { | |
125 do { | |
126 total += iter.next(); | |
127 } while (iter.hasNext()); | |
128 } | |
129 return total; | |
130 } | |
131 | |
132 // TODO(jmesserly): something like should exist on Map, either a method or a | |
133 // constructor, see bug #5340679 | |
134 static void copyMap(Map dest, Map source) { | |
135 for (final k in source.getKeys()) { | |
136 dest[k] = source[k]; | |
137 } | |
138 } | |
139 } | |
OLD | NEW |