2014-09-19 16:38:37 -07:00
|
|
|
library facade.collection;
|
|
|
|
|
|
2016-04-12 08:02:59 -07:00
|
|
|
import 'dart:collection' show IterableBase;
|
2015-06-30 13:19:20 -07:00
|
|
|
import 'dart:convert' show JsonEncoder;
|
2015-11-11 04:24:30 -08:00
|
|
|
export 'dart:core' show Iterator, Map, List, Set;
|
2015-01-22 11:52:36 +01:00
|
|
|
import 'dart:math' show max, min;
|
2014-09-19 16:38:37 -07:00
|
|
|
|
2015-06-30 13:19:20 -07:00
|
|
|
var jsonEncoder = new JsonEncoder();
|
|
|
|
|
|
2014-11-09 18:24:28 -05:00
|
|
|
class MapIterator extends Iterator<List> {
|
2015-01-29 09:50:49 -08:00
|
|
|
final Iterator _iterator;
|
|
|
|
|
final Map _map;
|
|
|
|
|
|
|
|
|
|
MapIterator(Map map)
|
|
|
|
|
: _map = map,
|
|
|
|
|
_iterator = map.keys.iterator;
|
|
|
|
|
|
|
|
|
|
bool moveNext() => _iterator.moveNext();
|
2014-11-09 18:24:28 -05:00
|
|
|
|
|
|
|
|
List get current {
|
2015-01-29 09:50:49 -08:00
|
|
|
return _iterator.current != null
|
|
|
|
|
? [_iterator.current, _map[_iterator.current]]
|
|
|
|
|
: null;
|
2014-11-09 18:24:28 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class IterableMap extends IterableBase<List> {
|
2015-01-29 09:50:49 -08:00
|
|
|
final Map _map;
|
2014-11-09 18:24:28 -05:00
|
|
|
|
2015-01-29 09:50:49 -08:00
|
|
|
IterableMap(Map map) : _map = map;
|
|
|
|
|
|
|
|
|
|
Iterator<List> get iterator => new MapIterator(_map);
|
2014-11-09 18:24:28 -05:00
|
|
|
}
|
|
|
|
|
|
2014-09-19 16:38:37 -07:00
|
|
|
class MapWrapper {
|
2016-02-19 11:49:31 -08:00
|
|
|
static Map/*<K,V>*/ clone/*<K,V>*/(Map/*<K,V>*/ m) => new Map.from(m);
|
2015-07-23 18:01:34 -07:00
|
|
|
|
|
|
|
|
// in opposite to JS, Dart does not create a new map
|
2016-02-19 11:49:31 -08:00
|
|
|
static Map/*<K,V>*/ createFromStringMap/*<K,V>*/(Map/*<K,V>*/ m) => m;
|
2015-07-23 18:01:34 -07:00
|
|
|
|
|
|
|
|
// in opposite to JS, Dart does not create a new map
|
2016-02-19 11:49:31 -08:00
|
|
|
static Map/*<K,V>*/ toStringMap/*<K,V>*/(Map/*<K,V>*/ m) => m;
|
2015-07-23 18:01:34 -07:00
|
|
|
|
2016-02-19 11:49:31 -08:00
|
|
|
static Map/*<K,V>*/ createFromPairs/*<K,V>*/(List pairs) => pairs.fold(/*<K,V>*/{}, (m, p) {
|
2015-08-04 12:05:30 -07:00
|
|
|
m[p[0]] = p[1];
|
|
|
|
|
return m;
|
|
|
|
|
});
|
|
|
|
|
|
2015-02-27 15:43:10 -08:00
|
|
|
static void clearValues(Map m) {
|
|
|
|
|
for (var k in m.keys) {
|
|
|
|
|
m[k] = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-08-04 12:05:30 -07:00
|
|
|
|
2016-02-19 11:49:31 -08:00
|
|
|
static Iterable/*<List<dynamic>>*/ iterable/*<K,V>*/(Map/*<K,V>*/ m) => new IterableMap(m);
|
|
|
|
|
static List/*<K>*/ keys/*<K,V>*/(Map/*<K,V>*/ m) => m.keys.toList();
|
|
|
|
|
static List/*<V>*/ values/*<K,V>*/(Map/*<K,V>*/ m) => m.values.toList();
|
2014-09-19 16:38:37 -07:00
|
|
|
}
|
|
|
|
|
|
2014-10-28 14:46:38 -07:00
|
|
|
class StringMapWrapper {
|
2016-02-19 11:49:31 -08:00
|
|
|
static Map/*<String,V>*/ create/*<V>*/() => {};
|
|
|
|
|
static bool contains/*<V>*/(Map/*<String,V>*/ map, String key) => map.containsKey(key);
|
|
|
|
|
static get/*<V>*/(Map/*<String,V>*/ map, String key) => map[key];
|
|
|
|
|
static void set/*<V>*/(Map/*<String,V>*/ map, String key, /*=V*/value) {
|
2014-10-28 14:46:38 -07:00
|
|
|
map[key] = value;
|
|
|
|
|
}
|
2015-08-04 12:05:30 -07:00
|
|
|
|
2016-02-19 11:49:31 -08:00
|
|
|
static void delete/*<V>*/(Map/*<String,V>*/ m, String k) {
|
2015-05-08 19:51:19 -07:00
|
|
|
m.remove(k);
|
2015-03-26 17:51:08 +01:00
|
|
|
}
|
2015-08-04 12:05:30 -07:00
|
|
|
|
2016-02-19 11:49:31 -08:00
|
|
|
static void forEach/*<V>*/(Map/*<String,V>*/ m, fn(/*=V*/ v, String k)) {
|
2015-01-29 09:50:49 -08:00
|
|
|
m.forEach((k, v) => fn(v, k));
|
2014-11-11 17:33:47 -08:00
|
|
|
}
|
2015-08-04 12:05:30 -07:00
|
|
|
|
2016-02-19 11:49:31 -08:00
|
|
|
static Map/*<String,V>*/ merge/*<V>*/(Map/*<String,V>*/ a, Map/*<String,V>*/ b) {
|
|
|
|
|
var m = new Map/*<String,V>*/.from(a);
|
2015-04-17 16:08:59 -07:00
|
|
|
if (b != null) {
|
|
|
|
|
b.forEach((k, v) => m[k] = v);
|
|
|
|
|
}
|
2015-02-11 11:10:31 -08:00
|
|
|
return m;
|
|
|
|
|
}
|
2015-08-04 12:05:30 -07:00
|
|
|
|
2015-05-12 14:14:43 -07:00
|
|
|
static List<String> keys(Map<String, dynamic> a) {
|
2015-05-11 12:31:16 -07:00
|
|
|
return a.keys.toList();
|
|
|
|
|
}
|
2015-08-04 12:05:30 -07:00
|
|
|
|
2016-03-06 20:20:55 -08:00
|
|
|
static List values(Map<String, dynamic> a) {
|
|
|
|
|
return a.values.toList();
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-29 09:50:49 -08:00
|
|
|
static bool isEmpty(Map m) => m.isEmpty;
|
2016-02-19 11:49:31 -08:00
|
|
|
static bool equals/*<V>*/(Map/*<String,V>*/ m1, Map/*<String,V>*/ m2) {
|
2015-05-11 09:08:37 -07:00
|
|
|
if (m1.length != m2.length) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
for (var key in m1.keys) {
|
|
|
|
|
if (m1[key] != m2[key]) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2014-10-28 14:46:38 -07:00
|
|
|
}
|
|
|
|
|
|
2015-06-26 11:10:52 -07:00
|
|
|
typedef bool Predicate<T>(T item);
|
|
|
|
|
|
2014-09-19 16:38:37 -07:00
|
|
|
class ListWrapper {
|
2016-02-19 11:49:31 -08:00
|
|
|
static List/*<T>*/ clone/*<T>*/(Iterable/*<T>*/ l) => new List.from(l);
|
|
|
|
|
static List/*<T>*/ createFixedSize/*<T>*/(int size) => new List(size);
|
|
|
|
|
static List/*<T>*/ createGrowableSize/*<T>*/(int size) =>
|
2015-06-22 17:52:34 -07:00
|
|
|
new List.generate(size, (_) => null, growable: true);
|
2015-08-04 12:05:30 -07:00
|
|
|
|
2015-01-29 09:50:49 -08:00
|
|
|
static bool contains(List m, k) => m.contains(k);
|
2015-05-08 19:51:19 -07:00
|
|
|
static int indexOf(List list, value, [int startIndex = 0]) =>
|
|
|
|
|
list.indexOf(value, startIndex);
|
2015-04-09 11:51:00 -07:00
|
|
|
static int lastIndexOf(List list, value, [int startIndex = null]) =>
|
|
|
|
|
list.lastIndexOf(value, startIndex == null ? list.length : startIndex);
|
2015-08-04 12:05:30 -07:00
|
|
|
|
2016-02-19 11:49:31 -08:00
|
|
|
static void forEachWithIndex/*<T>*/(List/*<T>*/ list, fn(/*=T*/ item, int index)) {
|
2015-08-19 11:26:45 -07:00
|
|
|
for (var i = 0; i < list.length; ++i) {
|
|
|
|
|
fn(list[i], i);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-02-19 11:49:31 -08:00
|
|
|
static /*=T*/ first/*<T>*/(List/*<T>*/ list) => list.isEmpty ? null : list.first;
|
|
|
|
|
static /*=T*/ last/*<T>*/(List/*<T>*/ list) => list.isEmpty ? null : list.last;
|
|
|
|
|
static List/*<T>*/ reversed/*<T>*/(List/*<T>*/ list) => list.reversed.toList();
|
|
|
|
|
static List/*<T>*/ concat/*<T>*/(List/*<T>*/ a, List/*<T>*/ b) {
|
2015-05-12 14:14:43 -07:00
|
|
|
return new List()
|
|
|
|
|
..length = a.length + b.length
|
|
|
|
|
..setRange(0, a.length, a)
|
|
|
|
|
..setRange(a.length, a.length + b.length, b);
|
2015-01-29 09:50:49 -08:00
|
|
|
}
|
2015-08-04 12:05:30 -07:00
|
|
|
|
2016-02-19 11:49:31 -08:00
|
|
|
static void insert/*<T>*/(List/*<T>*/ l, int index, /*=T*/ value) {
|
2015-01-29 09:50:49 -08:00
|
|
|
l.insert(index, value);
|
|
|
|
|
}
|
2015-08-04 12:05:30 -07:00
|
|
|
|
2015-01-30 09:43:21 +01:00
|
|
|
static removeAt(List l, int index) => l.removeAt(index);
|
2016-02-19 11:49:31 -08:00
|
|
|
static void removeAll/*<T>*/(List/*<T>*/ list, List/*<T>*/ items) {
|
2015-01-02 14:23:59 -08:00
|
|
|
for (var i = 0; i < items.length; ++i) {
|
|
|
|
|
list.remove(items[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-08-04 12:05:30 -07:00
|
|
|
|
2016-02-19 11:49:31 -08:00
|
|
|
static bool remove/*<T>*/(List/*<T>*/ list, /*=T*/ item) => list.remove(item);
|
2015-01-29 09:50:49 -08:00
|
|
|
static void clear(List l) {
|
|
|
|
|
l.clear();
|
|
|
|
|
}
|
2015-08-04 12:05:30 -07:00
|
|
|
|
2015-01-29 09:50:49 -08:00
|
|
|
static bool isEmpty(Iterable list) => list.isEmpty;
|
2016-02-19 11:49:31 -08:00
|
|
|
static void fill/*<T>*/(List/*<T>*/ l, /*=T*/ value, [int start = 0, int end]) {
|
2015-04-17 10:42:16 +02:00
|
|
|
l.fillRange(_startOffset(l, start), _endOffset(l, end), value);
|
2015-01-22 11:52:36 +01:00
|
|
|
}
|
2015-08-04 12:05:30 -07:00
|
|
|
|
2016-02-19 11:49:31 -08:00
|
|
|
static bool equals/*<T>*/(List/*<T>*/ a, List/*<T>*/ b) {
|
2015-01-29 09:50:49 -08:00
|
|
|
if (a.length != b.length) return false;
|
2015-01-25 16:59:06 -08:00
|
|
|
for (var i = 0; i < a.length; ++i) {
|
|
|
|
|
if (a[i] != b[i]) return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2015-08-04 12:05:30 -07:00
|
|
|
|
2016-02-19 11:49:31 -08:00
|
|
|
static List/*<T>*/ slice/*<T>*/(List/*<T>*/ l, [int from = 0, int to]) {
|
2015-08-30 17:05:02 -07:00
|
|
|
from = _startOffset(l, from);
|
|
|
|
|
to = _endOffset(l, to);
|
2015-08-30 17:03:37 -07:00
|
|
|
//in JS if from > to an empty array is returned
|
2015-10-20 09:38:14 -07:00
|
|
|
if (to != null && from > to) {
|
2015-08-30 17:03:37 -07:00
|
|
|
return [];
|
|
|
|
|
}
|
2015-08-30 17:05:02 -07:00
|
|
|
return l.sublist(from, to);
|
2015-02-05 18:33:57 -08:00
|
|
|
}
|
2015-08-04 12:05:30 -07:00
|
|
|
|
2016-02-19 11:49:31 -08:00
|
|
|
static List/*<T>*/ splice/*<T>*/(List/*<T>*/ l, int from, int length) {
|
2015-04-17 10:42:16 +02:00
|
|
|
from = _startOffset(l, from);
|
2015-04-17 13:20:03 -07:00
|
|
|
var to = from + length;
|
2015-04-16 16:29:46 -07:00
|
|
|
var sub = l.sublist(from, to);
|
|
|
|
|
l.removeRange(from, to);
|
|
|
|
|
return sub;
|
|
|
|
|
}
|
2015-08-04 12:05:30 -07:00
|
|
|
|
2016-02-19 11:49:31 -08:00
|
|
|
static void sort/*<T>*/(List/*<T>*/ l, [int compareFn(/*=T*/a, /*=T*/b) = null]) {
|
2015-05-22 17:47:13 +02:00
|
|
|
if (compareFn == null) {
|
|
|
|
|
l.sort();
|
|
|
|
|
} else {
|
|
|
|
|
l.sort(compareFn);
|
|
|
|
|
}
|
2015-02-18 14:39:52 -08:00
|
|
|
}
|
2015-04-17 10:42:16 +02:00
|
|
|
|
2015-06-30 13:19:20 -07:00
|
|
|
static String toJSON(List l) {
|
|
|
|
|
return jsonEncoder.convert(l);
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-17 10:42:16 +02:00
|
|
|
// JS splice, slice, fill functions can take start < 0 which indicates a position relative to
|
|
|
|
|
// the end of the list
|
|
|
|
|
static int _startOffset(List l, int start) {
|
|
|
|
|
int len = l.length;
|
2015-08-30 17:05:02 -07:00
|
|
|
return start < 0 ? max(len + start, 0) : min(start, len);
|
2015-04-17 10:42:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// JS splice, slice, fill functions can take end < 0 which indicates a position relative to
|
|
|
|
|
// the end of the list
|
|
|
|
|
static int _endOffset(List l, int end) {
|
|
|
|
|
int len = l.length;
|
|
|
|
|
if (end == null) return len;
|
|
|
|
|
return end < 0 ? max(len + end, 0) : min(end, len);
|
|
|
|
|
}
|
2015-08-13 11:19:37 -07:00
|
|
|
|
|
|
|
|
static maximum(List l, fn(item)) {
|
|
|
|
|
if (l.length == 0) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
var solution = null;
|
|
|
|
|
var maxValue = double.NEGATIVE_INFINITY;
|
|
|
|
|
for (var index = 0; index < l.length; index++) {
|
|
|
|
|
var candidate = l[index];
|
|
|
|
|
if (candidate == null) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
var candidateValue = fn(candidate);
|
|
|
|
|
if (candidateValue > maxValue) {
|
|
|
|
|
solution = candidate;
|
|
|
|
|
maxValue = candidateValue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return solution;
|
|
|
|
|
}
|
2016-02-17 09:17:29 -08:00
|
|
|
|
2016-03-23 13:42:19 -07:00
|
|
|
static List flatten(List l) {
|
2016-01-06 14:13:44 -08:00
|
|
|
var target = [];
|
|
|
|
|
_flattenArray(l, target);
|
|
|
|
|
return target;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static addAll(List l, List source) {
|
|
|
|
|
l.addAll(source);
|
2016-03-23 13:42:19 -07:00
|
|
|
}
|
2014-09-26 13:52:12 -07:00
|
|
|
}
|
|
|
|
|
|
2016-01-06 14:13:44 -08:00
|
|
|
List _flattenArray(List source, List target) {
|
|
|
|
|
if (source != null) {
|
|
|
|
|
for (var i = 0; i < source.length; i++) {
|
|
|
|
|
var item = source[i];
|
|
|
|
|
if (item is List) {
|
|
|
|
|
_flattenArray(item, target);
|
|
|
|
|
} else {
|
|
|
|
|
target.add(item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return target;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-11-24 18:42:53 +01:00
|
|
|
bool isListLikeIterable(obj) => obj is Iterable;
|
|
|
|
|
|
2016-02-19 11:49:31 -08:00
|
|
|
bool areIterablesEqual/*<T>*/(
|
|
|
|
|
Iterable/*<T>*/ a,
|
|
|
|
|
Iterable/*<T>*/ b,
|
|
|
|
|
bool comparator(/*=T*/a, /*=T*/b))
|
|
|
|
|
{
|
2016-01-05 13:42:21 -08:00
|
|
|
var iterator1 = a.iterator;
|
|
|
|
|
var iterator2 = b.iterator;
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
var done1 = !iterator1.moveNext();
|
|
|
|
|
var done2 = !iterator2.moveNext();
|
|
|
|
|
if (done1 && done2) return true;
|
|
|
|
|
if (done1 || done2) return false;
|
2016-02-19 11:49:31 -08:00
|
|
|
if (!comparator(iterator1.current, iterator2.current)) return false;
|
2016-01-05 13:42:21 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-19 11:49:31 -08:00
|
|
|
void iterateListLike/*<T>*/(Iterable/*<T>*/ iter, fn(/*=T*/item)) {
|
2014-11-24 18:42:53 +01:00
|
|
|
assert(iter is Iterable);
|
|
|
|
|
for (var item in iter) {
|
2015-01-29 09:50:49 -08:00
|
|
|
fn(item);
|
2014-11-24 18:42:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-26 13:52:12 -07:00
|
|
|
class SetWrapper {
|
2016-02-19 11:49:31 -08:00
|
|
|
static Set/*<T>*/ createFromList/*<T>*/(List/*<T>*/ l) => new Set.from(l);
|
|
|
|
|
static bool has/*<T>*/(Set/*<T>*/ s, /*=T*/key) => s.contains(key);
|
|
|
|
|
static void delete/*<T>*/(Set/*<T>*/ m, /*=T*/k) {
|
2015-07-24 15:28:44 -07:00
|
|
|
m.remove(k);
|
|
|
|
|
}
|
2014-09-19 16:38:37 -07:00
|
|
|
}
|