取消Extension改为linq.List以避免forin污染
This commit is contained in:
@@ -63,6 +63,7 @@ module es {
|
||||
public _frameCounterElapsedTime: number = 0;
|
||||
public _frameCounter: number = 0;
|
||||
public _totalMemory: number = 0;
|
||||
public _titleMemory: (totalMemory: number, frameCounter: number) => void;
|
||||
public _scene: Scene;
|
||||
|
||||
/**
|
||||
@@ -188,6 +189,7 @@ module es {
|
||||
if (memoryInfo != null) {
|
||||
this._totalMemory = Number((memoryInfo.totalJSHeapSize / 1048576).toFixed(2));
|
||||
}
|
||||
if (this._titleMemory) this._titleMemory(this._totalMemory, this._frameCounter);
|
||||
this._frameCounter = 0;
|
||||
this._frameCounterElapsedTime -= 1;
|
||||
}
|
||||
|
||||
@@ -343,10 +343,10 @@ module es {
|
||||
* 获取类型T的第一个组件并返回它。如果没有找到组件,将创建组件。
|
||||
* @param type
|
||||
*/
|
||||
public getOrCreateComponent<T extends Component>(type: T) {
|
||||
let comp = this.components.getComponent<T>(TypeUtils.getType(type), true);
|
||||
public getOrCreateComponent<T extends Component>(type) {
|
||||
let comp = this.components.getComponent<T>(type, true);
|
||||
if (!comp) {
|
||||
comp = this.addComponent<T>(type);
|
||||
comp = this.addComponent<T>(new type());
|
||||
}
|
||||
|
||||
return comp;
|
||||
|
||||
@@ -147,7 +147,7 @@ module es {
|
||||
*/
|
||||
public getSceneComponent<T extends SceneComponent>(type) {
|
||||
for (let i = 0; i < this._sceneComponents.length; i++) {
|
||||
let component = this._sceneComponents[i];
|
||||
let component = this._sceneComponents.buffer[i];
|
||||
if (component instanceof type)
|
||||
return component as T;
|
||||
}
|
||||
@@ -212,9 +212,10 @@ module es {
|
||||
* @param renderer
|
||||
*/
|
||||
public removeRenderer(renderer: Renderer) {
|
||||
if (!this._renderers.contains(renderer))
|
||||
let rendererList = new linq.List(this._renderers);
|
||||
if (!rendererList.contains(renderer))
|
||||
return;
|
||||
this._renderers.remove(renderer);
|
||||
rendererList.remove(renderer);
|
||||
renderer.unload();
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ module es {
|
||||
}
|
||||
|
||||
public onChanged(entity: Entity) {
|
||||
let contains = this._entities.contains(entity);
|
||||
let contains = new linq.List(this._entities).contains(entity);
|
||||
let interest = this._matcher.isInterestedEntity(entity);
|
||||
|
||||
if (interest && !contains)
|
||||
@@ -46,7 +46,7 @@ module es {
|
||||
}
|
||||
|
||||
public remove(entity: Entity) {
|
||||
this._entities.remove(entity);
|
||||
new linq.List(this._entities).remove(entity);
|
||||
this.onRemoved(entity);
|
||||
}
|
||||
|
||||
|
||||
@@ -268,8 +268,9 @@ module es {
|
||||
return this;
|
||||
|
||||
if (!this._parent) {
|
||||
this._parent._children.remove(this);
|
||||
this._parent._children.push(this);
|
||||
let children = new linq.List(this._parent._children);
|
||||
children.remove(this);
|
||||
children.add(this);
|
||||
}
|
||||
|
||||
this._parent = parent;
|
||||
|
||||
@@ -50,16 +50,18 @@ module es {
|
||||
}
|
||||
|
||||
public remove(component: Component) {
|
||||
if (this._componentsToRemove.contains(component))
|
||||
let componentToRemove = new linq.List(this._componentsToRemove);
|
||||
let componentToAdd = new linq.List(this._componentsToAdd);
|
||||
if (componentToRemove.contains(component))
|
||||
console.warn(`您正在尝试删除一个您已经删除的组件(${component})`);
|
||||
|
||||
// 这可能不是一个活动的组件,所以我们必须注意它是否还没有被处理,它可能正在同一帧中被删除
|
||||
if (this._componentsToAdd.contains(component)) {
|
||||
this._componentsToAdd.remove(component);
|
||||
if (componentToAdd.contains(component)) {
|
||||
componentToAdd.remove(component);
|
||||
return;
|
||||
}
|
||||
|
||||
this._componentsToRemove.push(component);
|
||||
componentToRemove.add(component);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -122,7 +122,7 @@ module es {
|
||||
public removeFromTagList(entity: Entity) {
|
||||
let list = this._entityDict.get(entity.tag);
|
||||
if (list) {
|
||||
list.remove(entity);
|
||||
new linq.List(list).remove(entity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ module es {
|
||||
}
|
||||
|
||||
public remove(processor: EntitySystem) {
|
||||
this._processors.remove(processor);
|
||||
new linq.List(this._processors).remove(processor);
|
||||
}
|
||||
|
||||
public onComponentAdded(entity: Entity) {
|
||||
|
||||
@@ -71,7 +71,7 @@ module es {
|
||||
throw new Error("index超出范围!");
|
||||
|
||||
this.length --;
|
||||
this.buffer.removeAt(index);
|
||||
new linq.List(this.buffer).removeAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,14 +36,15 @@ module es {
|
||||
}
|
||||
|
||||
public remove(component: IRenderable) {
|
||||
this._components.remove(component);
|
||||
this._componentsByRenderLayer.get(component.renderLayer).remove(component);
|
||||
new linq.List(this._components).remove(component);
|
||||
new linq.List(this._componentsByRenderLayer.get(component.renderLayer)).remove(component);
|
||||
}
|
||||
|
||||
public updateRenderableRenderLayer(component: IRenderable, oldRenderLayer: number, newRenderLayer: number) {
|
||||
// 需要注意的是,如果渲染层在组件update之前发生了改变
|
||||
if (this._componentsByRenderLayer.has(oldRenderLayer) && this._componentsByRenderLayer.get(oldRenderLayer).contains(component)) {
|
||||
this._componentsByRenderLayer.get(oldRenderLayer).remove(component);
|
||||
let oldRenderLayers = new linq.List(this._componentsByRenderLayer.get(oldRenderLayer));
|
||||
if (this._componentsByRenderLayer.has(oldRenderLayer) && oldRenderLayers.contains(component)) {
|
||||
oldRenderLayers.remove(component);
|
||||
this.addToRenderLayerList(component, newRenderLayer);
|
||||
}
|
||||
}
|
||||
@@ -53,8 +54,9 @@ module es {
|
||||
* @param renderLayer
|
||||
*/
|
||||
public setRenderLayerNeedsComponentSort(renderLayer: number) {
|
||||
if (!this._unsortedRenderLayers.contains(renderLayer))
|
||||
this._unsortedRenderLayers.push(renderLayer);
|
||||
let unsortedRenderLayers = new linq.List(this._unsortedRenderLayers);
|
||||
if (!unsortedRenderLayers.contains(renderLayer))
|
||||
unsortedRenderLayers.add(renderLayer);
|
||||
this.componentsNeedSort = true;
|
||||
}
|
||||
|
||||
@@ -63,15 +65,16 @@ module es {
|
||||
}
|
||||
|
||||
public addToRenderLayerList(component: IRenderable, renderLayer: number) {
|
||||
let list = this.componentsWithRenderLayer(renderLayer);
|
||||
let list = new linq.List(this.componentsWithRenderLayer(renderLayer));
|
||||
if (list.contains(component)) {
|
||||
console.warn("组件呈现层列表已经包含此组件");
|
||||
return;
|
||||
}
|
||||
|
||||
list.push(component);
|
||||
if (!this._unsortedRenderLayers.contains(renderLayer))
|
||||
this._unsortedRenderLayers.push(renderLayer);
|
||||
list.add(component);
|
||||
let unsortedRenderLayers = new linq.List(this._unsortedRenderLayers);
|
||||
if (!unsortedRenderLayers.contains(renderLayer))
|
||||
unsortedRenderLayers.add(renderLayer);
|
||||
this.componentsNeedSort = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,378 +0,0 @@
|
||||
declare interface Array<T> {
|
||||
/**
|
||||
* 获取满足表达式的数组元素索引
|
||||
* @param predicate 表达式
|
||||
*/
|
||||
findIndex(predicate: (c: T)=>boolean): number;
|
||||
|
||||
/**
|
||||
* 是否存在满足表达式的数组元素
|
||||
* @param predicate 表达式
|
||||
*/
|
||||
any(predicate: (c: T) => boolean): boolean;
|
||||
|
||||
/**
|
||||
* 获取满足表达式的第一个或默认数组元素
|
||||
* @param predicate 表达式
|
||||
*/
|
||||
firstOrDefault(predicate: (c: T)=>boolean): T;
|
||||
|
||||
/**
|
||||
* 获取满足表达式的第一个数组元素
|
||||
* @param predicate 表达式
|
||||
*/
|
||||
find(predicate: (c: T) => boolean): T;
|
||||
|
||||
/**
|
||||
* 筛选满足表达式的数组元素
|
||||
* @param predicate 表达式
|
||||
*/
|
||||
where(predicate: (c: T) => boolean): Array<T>;
|
||||
|
||||
/**
|
||||
* 获取满足表达式的数组元素的计数
|
||||
* @param predicate 表达式
|
||||
*/
|
||||
count(predicate: (c: T) => boolean): number;
|
||||
|
||||
/**
|
||||
* 获取满足表达式的数组元素的数组
|
||||
* @param predicate 表达式
|
||||
*/
|
||||
findAll(predicate: (c: T) => boolean): Array<T>;
|
||||
|
||||
/**
|
||||
* 是否有获取满足表达式的数组元素
|
||||
* @param value 值
|
||||
*/
|
||||
contains(value: T): boolean;
|
||||
|
||||
/**
|
||||
* 移除满足表达式的数组元素
|
||||
* @param predicate 表达式
|
||||
*/
|
||||
removeAll(predicate: (c: T) => boolean): void;
|
||||
|
||||
/**
|
||||
* 移除数组元素
|
||||
* @param element 数组元素
|
||||
*/
|
||||
remove(element: T): boolean;
|
||||
|
||||
/**
|
||||
* 移除特定索引数组元素
|
||||
* @param index 索引
|
||||
*/
|
||||
removeAt(index: number): void;
|
||||
|
||||
/**
|
||||
* 移除范围数组元素
|
||||
* @param index 开始索引
|
||||
* @param count 删除的个数
|
||||
*/
|
||||
removeRange(index: number, count: number): void;
|
||||
|
||||
/**
|
||||
* 获取通过选择器转换的数组
|
||||
* @param selector 选择器
|
||||
*/
|
||||
select(selector: Function): Array<T>;
|
||||
|
||||
/**
|
||||
* 排序(升序)
|
||||
* @param keySelector key选择器
|
||||
* @param comparer 比较器
|
||||
*/
|
||||
orderBy(keySelector: Function, comparer: Function): Array<T>;
|
||||
|
||||
/**
|
||||
* 排序(降序)
|
||||
* @param keySelector key选择器
|
||||
* @param comparer 比较器
|
||||
*/
|
||||
orderByDescending(keySelector: Function, comparer: Function): Array<T>;
|
||||
|
||||
/**
|
||||
* 分组
|
||||
* @param keySelector key选择器
|
||||
*/
|
||||
groupBy(keySelector: Function): Array<T>;
|
||||
|
||||
/**
|
||||
* 求和
|
||||
* @param selector 选择器
|
||||
*/
|
||||
sum(selector: Function): number;
|
||||
}
|
||||
|
||||
Array.prototype.findIndex = function (predicate) {
|
||||
function findIndex(array, predicate) {
|
||||
for (let i = 0, len = array.length; i < len; i++) {
|
||||
if (predicate.call(arguments[2], array[i], i, array)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return findIndex(this, predicate);
|
||||
};
|
||||
|
||||
Array.prototype.any = function (predicate) {
|
||||
function any(array, predicate) {
|
||||
return array.findIndex(predicate) > -1;
|
||||
}
|
||||
|
||||
return any(this, predicate);
|
||||
};
|
||||
|
||||
Array.prototype.firstOrDefault = function (predicate) {
|
||||
function firstOrDefault(array, predicate) {
|
||||
let index = array.findIndex(predicate);
|
||||
return index == -1 ? null : array[index];
|
||||
}
|
||||
|
||||
return firstOrDefault(this, predicate);
|
||||
};
|
||||
|
||||
Array.prototype.find = function (predicate) {
|
||||
function find(array, predicate) {
|
||||
return array.firstOrDefault(predicate);
|
||||
}
|
||||
|
||||
return find(this, predicate);
|
||||
};
|
||||
|
||||
Array.prototype.where = function (predicate) {
|
||||
function where(array, predicate) {
|
||||
if (typeof (array.reduce) === "function") {
|
||||
return array.reduce(function (ret, element, index) {
|
||||
if (predicate.call(arguments[2], element, index, array)) {
|
||||
ret.push(element);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}, []);
|
||||
} else {
|
||||
let ret = [];
|
||||
for (let i = 0, len = array.length; i < len; i++) {
|
||||
let element = array[i];
|
||||
if (predicate.call(arguments[2], element, i, array)) {
|
||||
ret.push(element);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return where(this, predicate);
|
||||
};
|
||||
|
||||
Array.prototype.count = function (predicate) {
|
||||
function count(array, predicate) {
|
||||
return array.where(predicate).length;
|
||||
}
|
||||
|
||||
return count(this, predicate);
|
||||
};
|
||||
|
||||
Array.prototype.findAll = function (predicate) {
|
||||
function findAll(array, predicate) {
|
||||
return array.where(predicate);
|
||||
}
|
||||
|
||||
return findAll(this, predicate);
|
||||
};
|
||||
|
||||
Array.prototype.contains = function (value) {
|
||||
function contains(array, value) {
|
||||
for (let i = 0, len = array.length; i < len; i++) {
|
||||
if (array[i] == value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return contains(this, value);
|
||||
};
|
||||
|
||||
Array.prototype.removeAll = function (predicate) {
|
||||
function removeAll(array, predicate) {
|
||||
let index;
|
||||
do {
|
||||
index = array.findIndex(predicate);
|
||||
if (index >= 0) {
|
||||
array.splice(index, 1);
|
||||
}
|
||||
}
|
||||
while (index >= 0)
|
||||
}
|
||||
|
||||
removeAll(this, predicate);
|
||||
};
|
||||
|
||||
Array.prototype.remove = function (element) {
|
||||
function remove(array, element) {
|
||||
let index = array.findIndex(function (x) {
|
||||
return x === element;
|
||||
});
|
||||
|
||||
if (index >= 0) {
|
||||
array.splice(index, 1);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return remove(this, element);
|
||||
};
|
||||
|
||||
Array.prototype.removeAt = function (index) {
|
||||
function removeAt(array, index) {
|
||||
array.splice(index, 1);
|
||||
}
|
||||
|
||||
return removeAt(this, index);
|
||||
};
|
||||
|
||||
Array.prototype.removeRange = function (index, count) {
|
||||
function removeRange(array, index, count) {
|
||||
array.splice(index, count);
|
||||
}
|
||||
|
||||
return removeRange(this, index, count);
|
||||
};
|
||||
|
||||
Array.prototype.select = function (selector) {
|
||||
function select(array, selector) {
|
||||
if (typeof (array.reduce) === "function") {
|
||||
return array.reduce(function (ret, element, index) {
|
||||
ret.push(selector.call(arguments[2], element, index, array));
|
||||
return ret;
|
||||
}, []);
|
||||
} else {
|
||||
let ret = [];
|
||||
for (let i = 0, len = array.length; i < len; i++) {
|
||||
ret.push(selector.call(arguments[2], array[i], i, array))
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return select(this, selector);
|
||||
};
|
||||
|
||||
Array.prototype.orderBy = function (keySelector, comparer) {
|
||||
function orderBy(array, keySelector, comparer) {
|
||||
array.sort(function (x, y) {
|
||||
let v1 = keySelector(x);
|
||||
let v2 = keySelector(y);
|
||||
if (comparer) {
|
||||
return comparer(v1, v2);
|
||||
} else {
|
||||
return (v1 > v2) ? 1 : -1;
|
||||
}
|
||||
});
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
return orderBy(this, keySelector, comparer);
|
||||
};
|
||||
|
||||
Array.prototype.orderByDescending = function (keySelector, comparer) {
|
||||
function orderByDescending(array, keySelector, comparer) {
|
||||
array.sort(function (x, y) {
|
||||
let v1 = keySelector(x);
|
||||
let v2 = keySelector(y);
|
||||
if (comparer) {
|
||||
return -comparer(v1, v2);
|
||||
} else {
|
||||
return (v1 < v2) ? 1 : -1;
|
||||
}
|
||||
});
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
return orderByDescending(this, keySelector, comparer);
|
||||
};
|
||||
|
||||
Array.prototype.groupBy = function (keySelector) {
|
||||
function groupBy(array, keySelector) {
|
||||
if (typeof (array.reduce) === "function") {
|
||||
let keys = [];
|
||||
return array.reduce(function (groups, element, index) {
|
||||
let key = JSON.stringify(keySelector.call(arguments[1], element, index, array));
|
||||
let index2 = keys.findIndex(function (x) {
|
||||
return x === key;
|
||||
});
|
||||
|
||||
if (index2 < 0) {
|
||||
index2 = keys.push(key) - 1;
|
||||
}
|
||||
|
||||
if (!groups[index2]) {
|
||||
groups[index2] = [];
|
||||
}
|
||||
|
||||
groups[index2].push(element);
|
||||
return groups;
|
||||
}, []);
|
||||
} else {
|
||||
let groups = [];
|
||||
let keys = [];
|
||||
for (let i = 0, len = array.length; i < len; i++) {
|
||||
let key = JSON.stringify(keySelector.call(arguments[1], array[i], i, array));
|
||||
let index = keys.findIndex(function (x) {
|
||||
return x === key;
|
||||
});
|
||||
|
||||
if (index < 0) {
|
||||
index = keys.push(key) - 1;
|
||||
}
|
||||
|
||||
if (!groups[index]) {
|
||||
groups[index] = [];
|
||||
}
|
||||
|
||||
groups[index].push(array[i]);
|
||||
}
|
||||
|
||||
return groups;
|
||||
}
|
||||
}
|
||||
|
||||
return groupBy(this, keySelector);
|
||||
};
|
||||
|
||||
Array.prototype.sum = function (selector) {
|
||||
function sum(array, selector) {
|
||||
let ret;
|
||||
for (let i = 0, len = array.length; i < len; i++) {
|
||||
if (i == 0) {
|
||||
if (selector) {
|
||||
ret = selector.call(arguments[2], array[i], i, array);
|
||||
} else {
|
||||
ret = array[i];
|
||||
}
|
||||
} else {
|
||||
if (selector) {
|
||||
ret += selector.call(arguments[2], array[i], i, array);
|
||||
} else {
|
||||
ret += array[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return sum(this, selector);
|
||||
};
|
||||
@@ -74,7 +74,7 @@ module es {
|
||||
if (!cell)
|
||||
console.log(`从不存在碰撞器的单元格中移除碰撞器: [${collider}]`);
|
||||
else
|
||||
cell.remove(collider);
|
||||
new linq.List(cell).remove(collider);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -281,8 +281,9 @@ module es {
|
||||
*/
|
||||
public remove(obj: Collider) {
|
||||
this._store.forEach(list => {
|
||||
if (list.contains(obj))
|
||||
list.remove(obj);
|
||||
let linqList = new linq.List(list);
|
||||
if (linqList.contains(obj))
|
||||
linqList.remove(obj);
|
||||
})
|
||||
}
|
||||
|
||||
@@ -334,7 +335,7 @@ module es {
|
||||
let potential = cell[i];
|
||||
|
||||
// 管理我们已经处理过的碰撞器
|
||||
if (this._checkedColliders.contains(potential))
|
||||
if (new linq.List(this._checkedColliders).contains(potential))
|
||||
continue;
|
||||
|
||||
this._checkedColliders.push(potential);
|
||||
|
||||
@@ -255,7 +255,7 @@ class ArrayUtils {
|
||||
* @param item
|
||||
*/
|
||||
public static addIfNotPresent<T>(list: T[], item: T) {
|
||||
if (list.contains(item))
|
||||
if (new linq.List(list).contains(item))
|
||||
return false;
|
||||
|
||||
list.push(item);
|
||||
|
||||
@@ -51,7 +51,7 @@ module es {
|
||||
let messageData = this._messageTable.get(eventType);
|
||||
let index = messageData.findIndex(data => data.func == handler);
|
||||
if (index != -1)
|
||||
messageData.removeAt(index);
|
||||
new linq.List(messageData).removeAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
25
source/src/Utils/Linq/enumerable.ts
Normal file
25
source/src/Utils/Linq/enumerable.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
module linq {
|
||||
export class Enumerable {
|
||||
/**
|
||||
* 在指定范围内生成一个整数序列。
|
||||
*/
|
||||
public static range(start: number, count: number): List<number> {
|
||||
let result = new List<number>();
|
||||
while (count--) {
|
||||
result.add(start++)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成包含一个重复值的序列。
|
||||
*/
|
||||
public static repeat<T>(element: T, count: number): List<T> {
|
||||
let result = new List<T>();
|
||||
while (count--) {
|
||||
result.add(element)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
38
source/src/Utils/Linq/helpers.ts
Normal file
38
source/src/Utils/Linq/helpers.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
module linq {
|
||||
/**
|
||||
* 检查传递的参数是否为对象
|
||||
*/
|
||||
export const isObj = <T>(x: T): boolean => !!x && typeof x === 'object';
|
||||
|
||||
/**
|
||||
* 创建一个否定谓词结果的函数
|
||||
*/
|
||||
export const negate = <T>(
|
||||
pred: (...args: T[]) => boolean
|
||||
): ((...args: T[]) => boolean) => (...args) => !pred(...args);
|
||||
|
||||
/**
|
||||
* 比较器助手
|
||||
*/
|
||||
|
||||
export const composeComparers = <T>(
|
||||
previousComparer: (a: T, b: T) => number,
|
||||
currentComparer: (a: T, b: T) => number
|
||||
): ((a: T, b: T) => number) => (a: T, b: T) =>
|
||||
previousComparer(a, b) || currentComparer(a, b);
|
||||
|
||||
export const keyComparer = <T>(
|
||||
_keySelector: (key: T) => string,
|
||||
descending?: boolean
|
||||
): ((a: T, b: T) => number) => (a: T, b: T) => {
|
||||
const sortKeyA = _keySelector(a);
|
||||
const sortKeyB = _keySelector(b);
|
||||
if (sortKeyA > sortKeyB) {
|
||||
return !descending ? 1 : -1
|
||||
} else if (sortKeyA < sortKeyB) {
|
||||
return !descending ? -1 : 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
};
|
||||
}
|
||||
644
source/src/Utils/Linq/list.ts
Normal file
644
source/src/Utils/Linq/list.ts
Normal file
@@ -0,0 +1,644 @@
|
||||
module linq {
|
||||
type PredicateType<T> = (value?: T, index?: number, list?: T[]) => boolean
|
||||
|
||||
export class List<T> {
|
||||
protected _elements: T[];
|
||||
|
||||
/**
|
||||
* 默认为列表的元素
|
||||
*/
|
||||
constructor(elements: T[] = []) {
|
||||
this._elements = elements
|
||||
}
|
||||
|
||||
/**
|
||||
* 在列表的末尾添加一个对象。
|
||||
*/
|
||||
public add(element: T): void {
|
||||
this._elements.push(element)
|
||||
}
|
||||
|
||||
/**
|
||||
* 将一个对象追加到列表的末尾。
|
||||
*/
|
||||
public append(element: T): void {
|
||||
this.add(element)
|
||||
}
|
||||
|
||||
/**
|
||||
* 在列表的开头添加一个对象。
|
||||
*/
|
||||
public prepend(element: T): void {
|
||||
this._elements.unshift(element)
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定集合的元素添加到列表的末尾。
|
||||
*/
|
||||
public addRange(elements: T[]): void {
|
||||
this._elements.push(...elements)
|
||||
}
|
||||
|
||||
/**
|
||||
* 对序列应用累加器函数。
|
||||
*/
|
||||
public aggregate<U>(
|
||||
accumulator: (accum: U, value?: T, index?: number, list?: T[]) => any,
|
||||
initialValue?: U
|
||||
): any {
|
||||
return this._elements.reduce(accumulator, initialValue)
|
||||
}
|
||||
|
||||
/**
|
||||
* 确定序列的所有元素是否满足一个条件。
|
||||
*/
|
||||
public all(predicate: PredicateType<T>): boolean {
|
||||
return this._elements.every(predicate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 确定序列是否包含任何元素。
|
||||
*/
|
||||
public any(): boolean
|
||||
public any(predicate: PredicateType<T>): boolean
|
||||
public any(predicate?: PredicateType<T>): boolean {
|
||||
return predicate
|
||||
? this._elements.some(predicate)
|
||||
: this._elements.length > 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算通过对输入序列的每个元素调用转换函数获得的一系列数值的平均值。
|
||||
*/
|
||||
public average(): number
|
||||
public average(
|
||||
transform: (value?: T, index?: number, list?: T[]) => any
|
||||
): number
|
||||
public average(
|
||||
transform?: (value?: T, index?: number, list?: T[]) => any
|
||||
): number {
|
||||
return this.sum(transform) / this.count(transform)
|
||||
}
|
||||
|
||||
/**
|
||||
* 将序列的元素转换为指定的类型。
|
||||
*/
|
||||
public cast<U>(): List<U> {
|
||||
return new List<U>(this._elements as any)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从列表中删除所有元素。
|
||||
*/
|
||||
public clear(): void {
|
||||
this._elements.length = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接两个序列。
|
||||
*/
|
||||
public concat(list: List<T>): List<T> {
|
||||
return new List<T>(this._elements.concat(list.toArray()))
|
||||
}
|
||||
|
||||
/**
|
||||
* 确定一个元素是否在列表中。
|
||||
*/
|
||||
public contains(element: T): boolean {
|
||||
return this.any(x => x === element)
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回序列中元素的数量。
|
||||
*/
|
||||
public count(): number
|
||||
public count(predicate: PredicateType<T>): number
|
||||
public count(predicate?: PredicateType<T>): number {
|
||||
return predicate ? this.where(predicate).count() : this._elements.length
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回指定序列的元素,或者如果序列为空,则返回单例集合中类型参数的默认值。
|
||||
*/
|
||||
public defaultIfEmpty(defaultValue?: T): List<T> {
|
||||
return this.count() ? this : new List<T>([defaultValue])
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指定的键选择器从序列中返回不同的元素。
|
||||
*/
|
||||
public distinctBy(keySelector: (key: T) => string | number): List<T> {
|
||||
const groups = this.groupBy(keySelector);
|
||||
return Object.keys(groups).reduce((res, key) => {
|
||||
res.add(groups[key][0] as T);
|
||||
return res
|
||||
}, new List<T>())
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回序列中指定索引处的元素。
|
||||
*/
|
||||
public elementAt(index: number): T {
|
||||
if (index < this.count() && index >= 0) {
|
||||
return this._elements[index]
|
||||
} else {
|
||||
throw new Error(
|
||||
'ArgumentOutOfRangeException: index is less than 0 or greater than or equal to the number of elements in source.'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回序列中指定索引处的元素,如果索引超出范围,则返回默认值。
|
||||
*/
|
||||
public elementAtOrDefault(index: number): T | null {
|
||||
return index < this.count() && index >= 0
|
||||
? this._elements[index]
|
||||
: undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过使用默认的相等比较器来比较值,生成两个序列的差值集。
|
||||
*/
|
||||
public except(source: List<T>): List<T> {
|
||||
return this.where(x => !source.contains(x))
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回序列的第一个元素。
|
||||
*/
|
||||
public first(): T
|
||||
public first(predicate: PredicateType<T>): T
|
||||
public first(predicate?: PredicateType<T>): T {
|
||||
if (this.count()) {
|
||||
return predicate ? this.where(predicate).first() : this._elements[0]
|
||||
} else {
|
||||
throw new Error(
|
||||
'InvalidOperationException: The source sequence is empty.'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回序列的第一个元素,如果序列不包含元素,则返回默认值。
|
||||
*/
|
||||
public firstOrDefault(): T
|
||||
public firstOrDefault(predicate: PredicateType<T>): T
|
||||
public firstOrDefault(predicate?: PredicateType<T>): T {
|
||||
return this.count(predicate) ? this.first(predicate) : undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* 对列表中的每个元素执行指定的操作。
|
||||
*/
|
||||
public forEach(action: (value?: T, index?: number, list?: T[]) => any): void {
|
||||
return this._elements.forEach(action)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指定的键选择器函数对序列中的元素进行分组。
|
||||
*/
|
||||
public groupBy<TResult>(
|
||||
grouper: (key: T) => string | number,
|
||||
mapper: (element: T) => TResult = val => (val as any) as TResult
|
||||
): { [key: string]: TResult[] } {
|
||||
const initialValue: { [key: string]: TResult[] } = {};
|
||||
return this.aggregate((ac, v: any) => {
|
||||
const key = grouper(v);
|
||||
const existingGroup = ac[key];
|
||||
const mappedValue = mapper(v);
|
||||
existingGroup
|
||||
? existingGroup.push(mappedValue)
|
||||
: (ac[key] = [mappedValue]);
|
||||
return ac
|
||||
}, initialValue)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据键的相等将两个序列的元素关联起来,并将结果分组。默认的相等比较器用于比较键。
|
||||
*/
|
||||
public groupJoin<U, R>(
|
||||
list: List<U>,
|
||||
key1: (k: T) => any,
|
||||
key2: (k: U) => any,
|
||||
result: (first: T, second: List<U>) => R
|
||||
): List<R> {
|
||||
return this.select(x =>
|
||||
result(
|
||||
x,
|
||||
list.where(z => key1(x) === key2(z))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回列表中某个元素第一次出现的索引。
|
||||
*/
|
||||
public indexOf(element: T): number {
|
||||
return this._elements.indexOf(element)
|
||||
}
|
||||
|
||||
/**
|
||||
* 向列表中插入一个元素在指定索引处。
|
||||
*/
|
||||
public insert(index: number, element: T): void | Error {
|
||||
if (index < 0 || index > this._elements.length) {
|
||||
throw new Error('Index is out of range.')
|
||||
}
|
||||
|
||||
this._elements.splice(index, 0, element)
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过使用默认的相等比较器来比较值,生成两个序列的交集集。
|
||||
*/
|
||||
public intersect(source: List<T>): List<T> {
|
||||
return this.where(x => source.contains(x))
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于匹配的键将两个序列的元素关联起来。默认的相等比较器用于比较键。
|
||||
*/
|
||||
public join<U, R>(
|
||||
list: List<U>,
|
||||
key1: (key: T) => any,
|
||||
key2: (key: U) => any,
|
||||
result: (first: T, second: U) => R
|
||||
): List<R> {
|
||||
return this.selectMany(x =>
|
||||
list.where(y => key2(y) === key1(x)).select(z => result(x, z))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回序列的最后一个元素。
|
||||
*/
|
||||
public last(): T
|
||||
public last(predicate: PredicateType<T>): T
|
||||
public last(predicate?: PredicateType<T>): T {
|
||||
if (this.count()) {
|
||||
return predicate
|
||||
? this.where(predicate).last()
|
||||
: this._elements[this.count() - 1]
|
||||
} else {
|
||||
throw Error('InvalidOperationException: The source sequence is empty.')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回序列的最后一个元素,如果序列不包含元素,则返回默认值。
|
||||
*/
|
||||
public lastOrDefault(): T
|
||||
public lastOrDefault(predicate: PredicateType<T>): T
|
||||
public lastOrDefault(predicate?: PredicateType<T>): T {
|
||||
return this.count(predicate) ? this.last(predicate) : undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回泛型序列中的最大值。
|
||||
*/
|
||||
public max(): number
|
||||
public max(selector: (value: T, index: number, array: T[]) => number): number
|
||||
public max(
|
||||
selector?: (value: T, index: number, array: T[]) => number
|
||||
): number {
|
||||
const id = x => x;
|
||||
return Math.max(...this._elements.map(selector || id))
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回泛型序列中的最小值。
|
||||
*/
|
||||
public min(): number
|
||||
public min(selector: (value: T, index: number, array: T[]) => number): number
|
||||
public min(
|
||||
selector?: (value: T, index: number, array: T[]) => number
|
||||
): number {
|
||||
const id = x => x;
|
||||
return Math.min(...this._elements.map(selector || id))
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指定的类型筛选序列中的元素。
|
||||
*/
|
||||
public ofType<U>(type: any): List<U> {
|
||||
let typeName;
|
||||
switch (type) {
|
||||
case Number:
|
||||
typeName = typeof 0;
|
||||
break;
|
||||
case String:
|
||||
typeName = typeof '';
|
||||
break;
|
||||
case Boolean:
|
||||
typeName = typeof true;
|
||||
break;
|
||||
case Function:
|
||||
typeName = typeof function () { }; // tslint:disable-line no-empty
|
||||
break;
|
||||
default:
|
||||
typeName = null;
|
||||
break
|
||||
}
|
||||
return typeName === null
|
||||
? this.where(x => x instanceof type).cast<U>()
|
||||
: this.where(x => typeof x === typeName).cast<U>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据键按升序对序列中的元素进行排序。
|
||||
*/
|
||||
public orderBy(
|
||||
keySelector: (key: T) => any,
|
||||
comparer = keyComparer(keySelector, false)
|
||||
): List<T> {
|
||||
// tslint:disable-next-line: no-use-before-declare
|
||||
return new OrderedList<T>(this._elements, comparer)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据键值降序对序列中的元素进行排序。
|
||||
*/
|
||||
public orderByDescending(
|
||||
keySelector: (key: T) => any,
|
||||
comparer = keyComparer(keySelector, true)
|
||||
): List<T> {
|
||||
// tslint:disable-next-line: no-use-before-declare
|
||||
return new OrderedList<T>(this._elements, comparer)
|
||||
}
|
||||
|
||||
/**
|
||||
* 按键按升序对序列中的元素执行后续排序。
|
||||
*/
|
||||
public thenBy(keySelector: (key: T) => any): List<T> {
|
||||
return this.orderBy(keySelector)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据键值按降序对序列中的元素执行后续排序。
|
||||
*/
|
||||
public thenByDescending(keySelector: (key: T) => any): List<T> {
|
||||
return this.orderByDescending(keySelector)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从列表中删除第一个出现的特定对象。
|
||||
*/
|
||||
public remove(element: T): boolean {
|
||||
return this.indexOf(element) !== -1
|
||||
? (this.removeAt(this.indexOf(element)), true)
|
||||
: false
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除与指定谓词定义的条件匹配的所有元素。
|
||||
*/
|
||||
public removeAll(predicate: PredicateType<T>): List<T> {
|
||||
return this.where(negate(predicate as any))
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除列表指定索引处的元素。
|
||||
*/
|
||||
public removeAt(index: number): void {
|
||||
this._elements.splice(index, 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* 颠倒整个列表中元素的顺序。
|
||||
*/
|
||||
public reverse(): List<T> {
|
||||
return new List<T>(this._elements.reverse())
|
||||
}
|
||||
|
||||
/**
|
||||
* 将序列中的每个元素投射到一个新形式中。
|
||||
*/
|
||||
public select<TOut>(
|
||||
selector: (element: T, index: number) => TOut
|
||||
): List<TOut> {
|
||||
return new List<TOut>(this._elements.map(selector))
|
||||
}
|
||||
|
||||
/**
|
||||
* 将序列的每个元素投影到一个列表中。并将得到的序列扁平化为一个序列。
|
||||
*/
|
||||
public selectMany<TOut extends List<any>>(
|
||||
selector: (element: T, index: number) => TOut
|
||||
): TOut {
|
||||
return this.aggregate(
|
||||
(ac, _, i) => (
|
||||
ac.addRange(
|
||||
this.select(selector)
|
||||
.elementAt(i)
|
||||
.toArray()
|
||||
),
|
||||
ac
|
||||
),
|
||||
new List<TOut>()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过使用默认的相等比较器对元素的类型进行比较,确定两个序列是否相等。
|
||||
*/
|
||||
public sequenceEqual(list: List<T>): boolean {
|
||||
return this.all(e => list.contains(e))
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回序列中唯一的元素,如果序列中没有恰好一个元素,则抛出异常。
|
||||
*/
|
||||
public single(predicate?: PredicateType<T>): T {
|
||||
if (this.count(predicate) !== 1) {
|
||||
throw new Error('The collection does not contain exactly one element.')
|
||||
} else {
|
||||
return this.first(predicate)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回序列中唯一的元素,如果序列为空,则返回默认值;如果序列中有多个元素,此方法将抛出异常。
|
||||
*/
|
||||
public singleOrDefault(predicate?: PredicateType<T>): T {
|
||||
return this.count(predicate) ? this.single(predicate) : undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* 绕过序列中指定数量的元素,然后返回剩余的元素。
|
||||
*/
|
||||
public skip(amount: number): List<T> {
|
||||
return new List<T>(this._elements.slice(Math.max(0, amount)))
|
||||
}
|
||||
|
||||
/**
|
||||
* 省略序列中最后指定数量的元素,然后返回剩余的元素。
|
||||
*/
|
||||
public skipLast(amount: number): List<T> {
|
||||
return new List<T>(this._elements.slice(0, -Math.max(0, amount)))
|
||||
}
|
||||
|
||||
/**
|
||||
* 只要指定条件为真,就绕过序列中的元素,然后返回剩余的元素。
|
||||
*/
|
||||
public skipWhile(predicate: PredicateType<T>): List<T> {
|
||||
return this.skip(
|
||||
this.aggregate(ac => (predicate(this.elementAt(ac)) ? ++ac : ac), 0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算通过对输入序列的每个元素调用转换函数获得的数值序列的和。
|
||||
*/
|
||||
public sum(): number
|
||||
public sum(
|
||||
transform: (value?: T, index?: number, list?: T[]) => number
|
||||
): number
|
||||
public sum(
|
||||
transform?: (value?: T, index?: number, list?: T[]) => number
|
||||
): number {
|
||||
return transform
|
||||
? this.select(transform).sum()
|
||||
: this.aggregate((ac, v) => (ac += +v), 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从序列的开始返回指定数量的连续元素。
|
||||
*/
|
||||
public take(amount: number): List<T> {
|
||||
return new List<T>(this._elements.slice(0, Math.max(0, amount)))
|
||||
}
|
||||
|
||||
/**
|
||||
* 从序列的末尾返回指定数目的连续元素。
|
||||
*/
|
||||
public takeLast(amount: number): List<T> {
|
||||
return new List<T>(this._elements.slice(-Math.max(0, amount)))
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回序列中的元素,只要指定的条件为真。
|
||||
*/
|
||||
public takeWhile(predicate: PredicateType<T>): List<T> {
|
||||
return this.take(
|
||||
this.aggregate(ac => (predicate(this.elementAt(ac)) ? ++ac : ac), 0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制列表中的元素到一个新数组。
|
||||
*/
|
||||
public toArray(): T[] {
|
||||
return this._elements
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个<dictionary>从List< T>根据指定的键选择器函数。
|
||||
*/
|
||||
public toDictionary<TKey>(
|
||||
key: (key: T) => TKey
|
||||
): List<{ Key: TKey; Value: T }>
|
||||
public toDictionary<TKey, TValue>(
|
||||
key: (key: T) => TKey,
|
||||
value: (value: T) => TValue
|
||||
): List<{ Key: TKey; Value: T | TValue }>
|
||||
public toDictionary<TKey, TValue>(
|
||||
key: (key: T) => TKey,
|
||||
value?: (value: T) => TValue
|
||||
): List<{ Key: TKey; Value: T | TValue }> {
|
||||
return this.aggregate((dicc, v, i) => {
|
||||
dicc[
|
||||
this.select(key)
|
||||
.elementAt(i)
|
||||
.toString()
|
||||
] = value ? this.select(value).elementAt(i) : v;
|
||||
dicc.add({
|
||||
Key: this.select(key).elementAt(i),
|
||||
Value: value ? this.select(value).elementAt(i) : v
|
||||
});
|
||||
return dicc
|
||||
}, new List<{ Key: TKey; Value: T | TValue }>())
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个Set从一个Enumerable.List< T>。
|
||||
*/
|
||||
public toSet() {
|
||||
let result = new Set();
|
||||
for (let x of this._elements)
|
||||
result.add(x);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个List< T>从一个Enumerable.List< T>。
|
||||
*/
|
||||
public toList(): List<T> {
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个查找,TElement>从一个IEnumerable< T>根据指定的键选择器和元素选择器函数。
|
||||
*/
|
||||
public toLookup<TResult>(
|
||||
keySelector: (key: T) => string | number,
|
||||
elementSelector: (element: T) => TResult
|
||||
): { [key: string]: TResult[] } {
|
||||
return this.groupBy(keySelector, elementSelector)
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于谓词过滤一系列值。
|
||||
*/
|
||||
public where(predicate: PredicateType<T>): List<T> {
|
||||
return new List<T>(this._elements.filter(predicate))
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定的函数应用于两个序列的对应元素,生成结果序列。
|
||||
*/
|
||||
public zip<U, TOut>(
|
||||
list: List<U>,
|
||||
result: (first: T, second: U) => TOut
|
||||
): List<TOut> {
|
||||
return list.count() < this.count()
|
||||
? list.select((x, y) => result(this.elementAt(y), x))
|
||||
: this.select((x, y) => result(x, list.elementAt(y)))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 表示已排序的序列。该类的方法是通过使用延迟执行来实现的。
|
||||
* 即时返回值是一个存储执行操作所需的所有信息的对象。
|
||||
* 在通过调用对象的ToDictionary、ToLookup、ToList或ToArray方法枚举对象之前,不会执行由该方法表示的查询
|
||||
*/
|
||||
export class OrderedList<T> extends List<T> {
|
||||
constructor(elements: T[], private _comparer: (a: T, b: T) => number) {
|
||||
super(elements);
|
||||
this._elements.sort(this._comparer)
|
||||
}
|
||||
|
||||
/**
|
||||
* 按键按升序对序列中的元素执行后续排序。
|
||||
* @override
|
||||
*/
|
||||
public thenBy(keySelector: (key: T) => any): List<T> {
|
||||
return new OrderedList(
|
||||
this._elements,
|
||||
composeComparers(this._comparer, keyComparer(keySelector, false))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据键值按降序对序列中的元素执行后续排序。
|
||||
* @override
|
||||
*/
|
||||
public thenByDescending(keySelector: (key: T) => any): List<T> {
|
||||
return new OrderedList(
|
||||
this._elements,
|
||||
composeComparers(this._comparer, keyComparer(keySelector, true))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ module es {
|
||||
for (let i = this._timers.length - 1; i >= 0; i --){
|
||||
if (this._timers[i].tick()){
|
||||
this._timers[i].unload();
|
||||
this._timers.removeAt(i);
|
||||
new linq.List(this._timers).removeAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user