package {
/**
* Collection Class
* Version 1.0, 2008-09-20
* Created by Michael James Williams
* <a href="http://www.michaeljameswilliams.com" >http://www.michaeljameswilliams.com</a>
*/
public class Collection extends Object {
public var _collection:Array;
/**
* Creates a new collection populated with the specified values
* @param ... values
*/
public function Collection(... values) {
_collection = new Array();
addItems(values);
}
/**
* Adds the specified items to the collection
* @param ... items
*/
public function addItems(... items):void {
for each (var item in items) {
if (item is Array) {
for each (var subItem in item) {
addItems(subItem);
}
} else if (item is Collection) {
for each (subItem in item.itemList) {
addItems(subItem);
}
} else {
if (!contains(item)) {
_collection.push(item);
}
}
}
}
/**
* Removes all of the specified items from the collection
* @param ... items
*/
public function removeItems(... items):void {
for each (var item in items) {
if (item is Array) {
for each (var subItem in item) {
removeItems(subItem);
}
} else if (item is Collection) {
for each (subItem in item.itemList) {
removeItems(subItem);
}
} else if (contains(item)) {
_collection.splice(_collection.indexOf(item), 1);
}
}
}
/**
* Returns true iff collection contains (or is) specified item
* @param item
* @return
*/
public function contains(item):Boolean {
if ((item is Array) || (item is Collection)) {
return containsAll(item);
} else {
if ((_collection.indexOf(item) > -1) || (this === item)) {
return true;
} else {
return false;
}
}
}
/**
* Returns true iff collection contains all specified items (including subitems of an array or collection)
* @param ... items
* @return
*/
public function containsAll(... items):Boolean {
var all:Boolean = true;
for each (var item in items) {
if (item is Array) {
for each (var subItem in item) {
if (!_collection.containsAll(subItem)) { all = false; }
}
} else if (item is Collection) {
for each (subItem in item.itemList) {
if (!_collection.containsAll(subItem)) { all = false; }
}
} else {
if (!_collection.contains(item)) { all = false; }
}
}
return all;
}
/**
* Returns true iff collection contains any of the specified items (including subitems of an array or collection)
* @param ... items
* @return
*/
public function containsAny(... items):Boolean {
var any:Boolean = false;
for each (var item in items) {
if (item is Array) {
for each (var subItem in item) {
if (!_collection.containsAny(subItem)) {
any = true;
break;
}
}
} else if (item is Collection) {
for each (subItem in item.itemList) {
if (!_collection.containsAny(subItem)) {
any = true;
break;
}
}
} else {
if (!_collection.contains(item)) {
any = true;
break;
}
}
}
return any;
}
/**
* Executes a test function on each item in the collection and constructs a new collection of all items that return true.
* @param callback
* @param thisObject
* @return
*/
public function filter(callback:Function, thisObject:* = null):Collection {
var filtered:Collection = new Collection();
filtered.addItems(_collection.filter(callback, thisObject));
return filtered;
}
/**
* Executes a function on each item in the collection.
* @param callback
* @param thisObject
*/
public function forEach(callback:Function, thisObject:* = null):void {
_collection.forEach(callback, thisObject);
}
/**
* Converts the elements in a collection to strings, inserts the specified separator between the elements, concatenates them, and returns the resulting string.
* @param sep
* @return
*/
public function join(sep:*):String {
return _collection.join(sep);
}
/**
* Executes a function on each item in an collection, and constructs a new collection of items corresponding to the results of the function on each item in the original collection.
* @param callback
* @param thisObject
* @return
*/
public function map(callback:Function, thisObject:* = null):Collection {
var mappedArray:Array = _collection.map(callback, thisObject);
var mappedCollection:Collection = new Collection();
for each (var item in mappedArray) {
mappedCollection.addItems(item);
}
return mappedCollection;
}
/**
* Executes a test function on each item in the collection until an item is reached that returns true. Use this method to determine whether any items in a collection meet a criterion, such as having a value less than a particular number.
* @param callback
* @param thisObject
* @return
*/
public function some(callback:Function, thisObject:* = null):Boolean {
return _collection.some(callback, thisObject);
}
/**
* Executes a test function on each item in the collection until an item is reached that returns false for the specified function. You use this method to determine whether all items in a collection meet a criterion, such as having values less than a particular number.
* @param callback
* @param thisObject
* @return
*/
public function every(callback:Function, thisObject:* = null):Boolean {
return _collection.every(callback, thisObject);
}
/**
* Returns a collection made up of items in this collection for which item.property==value
* @param property
* @param value
* @return
*/
public function subCollection(property:String, value:*):Collection {
///Ideally this would accept a method name and a ...params and check to see if item.method(...params)==true
var subCollection:Collection = new Collection();
for each (var item in _collection) {
try {
if (item[property]==value) {
subCollection.addItems(item);
}
} catch (err) {
//this is likely to be very very error prone if the programmer isn't careful so we'll just break out of the loop
break;
}
}
return subCollection;
}
/**
* Returns a collection made up of all items that are in both this collection and the specified collection
* @param coll
* @return
*/
public function intersection(coll:Collection):Collection {
var intersectColl:Collection=new Collection();
for each (var item in coll.itemList) {
if (this.contains(item)) {
intersectColl.addItems(item);
}
}
return intersectColl;
}
/**
* Returns the intersection of this collection with an arbitrary number of other collections
* @param ... colls
* @return
*/
public function intersectMany(... colls):Collection {
var intersectColl:Collection = new Collection();
intersectColl.addItems(_collection);
for each (var subItem in colls) {
if (subItem is Collection) {
intersectColl = intersectColl.intersection(subItem);
}
}
return intersectColl;
}
/**
* Returns a collection made up of all items that are in either this collection or the specified collection (or both)
* @param coll
* @return
*/
public function union(coll:Collection):Collection {
var unionColl:Collection = new Collection();
unionColl.addItems(itemList, coll);
return unionColl;
}
/**
* Returns the union of this collection with an arbitrary number of other collections
* @param ... colls
* @return
*/
public function unionMany(... colls):Collection {
var unionColl:Collection = new Collection();
unionColl.addItems(_collection);
for each (var subItem in colls) {
if (subItem is Collection) {
unionColl = unionColl.union(subItem);
}
}
return unionColl;
}
/**
* Returns the relative complement of the specified collection in this collection
* A.relComp(B) := AB
* @param coll
* @return
*/
public function relComp(coll):Collection {
///Returns the relative complement of the specified collection in this collection
///A.relComp(B) := AB
///i.e. returns a collection containing items that are in this collection but not in the specified collection
var rcColl:Collection = new Collection();
rcColl.addItems(_collection);
rcColl.removeItems(coll);
return rcColl;
}
/**
* Returns the relative complement of the union of the specified collections in this collection
* @param ... colls
* @return
*/
public function relCompMany(... colls):Collection {
var rcColl:Collection = new Collection();
rcColl.addItems(_collection);
for each (var subItem in colls) {
if (subItem is Collection) {
rcColl.removeItems(subItem);
}
}
return rcColl;
}
/**
* Returns the number of items in the collection
*/
public function get numItems():uint {
return _collection.length;
}
/**
* Exposes the underlying array; use this only for e.g. for-each loops
*/
public function get itemList():Array {
return _collection;
}
}
}
source