Files
sdk/client/util/CollectionUtils.dart
T
dgrove@google.com 4bc64b8c2b Initial checkin.
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@7 260f80e4-7a28-3924-810f-c04153c831b5
2011-10-05 04:52:33 +00:00

140 lines
4.1 KiB
Dart

// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
typedef num NumericValueSelector<T>(T value);
/**
* General purpose collection utilities.
* TODO(jmesserly): make these top level functions?
*/
class CollectionUtils {
static void insertAt(List arr, int pos, value) {
assert (pos >= 0);
assert (pos <= arr.length);
if (pos == arr.length) {
arr.add(value);
} else {
// TODO(sigmund): replace this push with a call that ensures capacity
// (currently not supported in the JS implementation of list). E.g.
// [: arr.length = arr.length + 1; :]
arr.add(null);
// shift elements from [pos] (note: arr already has null @ length - 1)
for (int i = arr.length - 2; i >= pos; i--) {
arr[i + 1] = arr[i];
}
arr[pos] = value;
// TODO(jmesserly): we won't need to do this once List
// implements insertAt
if (arr is ObservableList) {
// TODO(jmesserly): shouldn't need to cast after testing instanceof
ObservableList obs = arr;
obs.recordListInsert(pos, value);
}
}
}
// Collection<T> supports most of the ES 5 list methods, but it's missing
// map.
// TODO(jmesserly): we might want a version of this that return an iterable,
// however JS, Python and Ruby versions are all eager.
static List map(Iterable source, var mapper) {
// TODO(jmesserly): I was trying to set the capacity here, but instead it
// seems to create a fixed list. Hence assigning by index below.
List result = new List(source is List ? source.dynamic.length : null);
int i = 0;
for (final item in source) {
result[i++] = mapper(item);
}
return result;
}
/**
* Finds the item in [source] that matches [test]. Returns null if
* no item matches. The typing should be:
* T find(Iterable<T> source, bool test(T item)), but we don't have generic
* functions.
*/
static find(Iterable source, bool test(item)) {
for (final item in source) {
if (test(item)) return item;
}
return null;
}
/** Compute the minimum of an iterable. Returns null if empty. */
static num min(Iterable source) {
final iter = source.iterator();
if (!iter.hasNext()) {
return null;
}
num best = iter.next();
while (iter.hasNext()) {
best = Math.min(best, iter.next());
}
return best;
}
/** Compute the maximum of an iterable. Returns null if empty. */
static num max(Iterable source) {
final iter = source.iterator();
if (!iter.hasNext()) {
return null;
}
num best = iter.next();
while (iter.hasNext()) {
best = Math.max(best, iter.next());
}
return best;
}
/** Orders an iterable by its values, or by a key selector. */
static List orderBy(Iterable source, [NumericValueSelector selector = null]) {
final result = new List.from(source);
sortBy(result, selector);
return result;
}
/** Sorts a list by its values, or by a key selector. */
// TODO(jmesserly): we probably don't want to call the key selector more than
// once for a given element. This would improve performance and the API
// contract could be stronger.
static void sortBy(List list, [NumericValueSelector selector = null]) {
if (selector != null) {
list.sort((x, y) => selector(x) - selector(y));
} else {
list.sort((x, y) => x - y);
}
}
/** Compute the sum of an iterable. An empty iterable is an error. */
static num sum(Iterable source, [NumericValueSelector selector = null]) {
final iter = source.iterator();
num total = 0;
if (selector != null) {
do {
total += selector(iter.next());
} while (iter.hasNext());
} else {
do {
total += iter.next();
} while (iter.hasNext());
}
return total;
}
// TODO(jmesserly): something like should exist on Map, either a method or a
// constructor, see bug #5340679
static void copyMap(Map dest, Map source) {
for (final k in source.getKeys()) {
dest[k] = source[k];
}
}
}