b33097b9b4
BUG= R=sra@google.com Review-Url: https://codereview.chromium.org/2828603002 .
129 lines
3.7 KiB
Dart
129 lines
3.7 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.
|
|
|
|
part of utilslib;
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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.moveNext()) {
|
|
return null;
|
|
}
|
|
num best = iter.current;
|
|
while (iter.moveNext()) {
|
|
best = Math.min(best, iter.current);
|
|
}
|
|
return best;
|
|
}
|
|
|
|
/** Compute the maximum of an iterable. Returns null if empty. */
|
|
static num max(Iterable source) {
|
|
final iter = source.iterator;
|
|
if (!iter.moveNext()) {
|
|
return null;
|
|
}
|
|
num best = iter.current;
|
|
while (iter.moveNext()) {
|
|
best = Math.max(best, iter.current);
|
|
}
|
|
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;
|
|
bool wasEmpty = true;
|
|
num total = 0;
|
|
if (selector != null) {
|
|
for (var element in source) {
|
|
wasEmpty = false;
|
|
total += selector(element);
|
|
}
|
|
} else {
|
|
for (num element in source) {
|
|
wasEmpty = false;
|
|
total += element;
|
|
}
|
|
}
|
|
if (wasEmpty) throw new StateError("No elements");
|
|
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.keys) {
|
|
dest[k] = source[k];
|
|
}
|
|
}
|
|
}
|