那是自我隔离的另一天,我为自己做了一个项目,我们在开始后几天就放弃了。您会知道,使您成名的项目将使您学习新的编程语言,新的框架等。通常,这是最常见的一天,也是最常见的大流行病。没有什么预示着麻烦,直到我曾经使用过阵列的一个库因堆栈溢出而崩溃了……那时一切都开始冒出来。
总的来说,我完全理解可以使用现成的东西,但这并不是那么有趣。
为什么选择LINQ?
对于那些不认识的人,简要地:
LINQ(语言集成查询)是一种用于查询数据源的简单便捷的语言。实现IEnumerable接口的对象(例如,标准集合,数组),数据集,XML文档都可以充当数据源。
LINQ允许您执行以下操作:
string[] teams = { "", "", " ", " ", "", "" };
var selectedTeams = teams.Where(t=>t.ToUpper().StartsWith("")).OrderBy(t => t);
在特殊优势中,我想指出:
- 惰性计算
- 优化查询
- 方便的扩展方法系统
我不认识你,但对我个人来说,这是一个引人入胜的论点,以便着手工作。
入门
我想立即带着光剑走入生意,但我们不会那样做-我们通常是认真的人,会写严肃的东西。
因此,除了LINQ的优点所表明的以外,我们还将为自己设置一些要求:
- 代码应该易于扩展
- 代码应该很快
Benchmark.js. Lodash, , .
, , , , npm-.
, , , .
:
- Where
- Sort
- Min
, -, :
- Where , .
- Sort , .
- Min .
:
, :
, , , .
export class Collection<T> implements ICollection<T> {
protected inner: Collection<T>;
private _computed: T[] | null = null; // , ""
public where(condition: FilterCondition<T>): ICollection<T> {
return new FilteringCollection<T>(this, condition);
}
public sort(condition?: CompareCondition<T> | undefined): ICollection<T> {
return new SortingCollection<T>(this, {
compare: condition
})
}
public min(predicate?: CompareCondition<T> | undefined): T {
return new MinAggregator(this, predicate).aggregate();
}
public toArray(): T[] {
return this.computed;
}
public [Symbol.iterator](): IterableIterator<T> {
return this.getIterator();
}
public getIterator(): IterableIterator<T> {
return this.computed[Symbol.iterator](); // , for - of
}
private get computed(): T[] { // :
if (this._computed == null) {
const result = this.materialize();
Object.freeze(result);
this._computed = result;
}
return this._computed
}
protected materialize(): T[] { //
return this.inner.toArray();
}
}
" ?" — , : " ".
:
const collection = new Collection([6, 5, 4, 3, 2, 1]);
const result = collection.where(item => item % 2).sort(); // [1, 3, 5]
, :
const collection = new Collection([6, 5, 4, 3, 2, 1]);
/* 1) */const filtered = collection.where(item => item % 2);
/* 2) */const sorted = filtered.sort();
1) where
Collection
, inner
.
2) sort
FilteringCollection
, inner
.
, , :
1) materialize
FilteringCollection
[5, 3, 1]
.
2) materialize
SortingCollection
[1, 3, 5]
.
Where
export class FilteringCollection<T> extends Collection<T> {
public constructor(iterable: Collection<T> | T[], private condition: FilterCondition<T>) {
super(iterable);
}
public where(condition: FilterCondition<T>): ICollection<T> { // where
const result = new FilteringCollection<T>(this.inner, item => condition(item) && that.condition(item));
return result;
}
protected materialize(): T[] { //
return this.inner.toArray().filter(this.condition);
}
}
. .
, where(). , ?
, where:
_(cats).where(cat => cat.age < 3).where(cat => cat.age > 1).toArray()
_(cats).where(cat => cat.age < 3 && (function(item){
return item.age > 1;
}(cat))).toArray()
:
public where(condition: FilterCondition<T>): ICollection<T> { // where
const result = new FilteringCollection<T>(this.inner, item => condition(item) && this.condition(item)); // <--
return result;
}
"".
materialize
filter
. . , .
----------------------------------------------------
Filter for 1000000:
Where x 104 ops/sec ±14.73% (61 runs sampled)
Lodash filter x 609 ops/sec ±0.67% (88 runs sampled)
Native filter x 537 ops/sec ±1.69% (85 runs sampled)
Double where x 102 ops/sec ±11.51% (64 runs sampled)
Double lodash filter x 368 ops/sec ±1.00% (88 runs sampled)
Double native filter x 336 ops/sec ±1.08% (84 runs sampled)
10 where x 66.60 ops/sec ±9.15% (59 runs sampled)
10 lodash filter x 99.44 ops/sec ±1.20% (73 runs sampled)
10 native filter x 81.80 ops/sec ±1.33% (70 runs sampled)
----------------------------------------------------
Filter for 1000:
Where x 24,296 ops/sec ±0.90% (88 runs sampled)
Lodash filter x 60,927 ops/sec ±0.90% (89 runs sampled)
Native filter x 204,522 ops/sec ±6.76% (87 runs sampled)
Double where x 20,281 ops/sec ±0.86% (90 runs sampled)
Double lodash filter x 37,553 ops/sec ±0.97% (90 runs sampled)
Double native filter x 115,652 ops/sec ±6.12% (91 runs sampled)
10 where x 9,559 ops/sec ±1.09% (87 runs sampled)
10 lodash filter x 8,850 ops/sec ±0.80% (87 runs sampled)
10 native filter x 22,507 ops/sec ±9.22% (84 runs sampled)
----------------------------------------------------
Filter for 10:
Where x 1,788,009 ops/sec ±0.81% (87 runs sampled)
Lodash filter x 720,558 ops/sec ±0.80% (84 runs sampled)
Native filter x 14,917,151 ops/sec ±0.61% (85 runs sampled)
Double where x 1,257,163 ops/sec ±0.52% (95 runs sampled)
Double lodash filter x 456,365 ops/sec ±0.74% (76 runs sampled)
Double native filter x 8,262,940 ops/sec ±0.64% (90 runs sampled)
10 where x 489,733 ops/sec ±0.67% (94 runs sampled)
10 lodash filter x 135,275 ops/sec ±0.61% (94 runs sampled)
10 native filter x 1,350,316 ops/sec ±0.94% (90 runs sampled)
----------------------------------------------------
: , .
select ( ).
Sort
export class SortingCollection<T, V = T> extends Collection<T> implements ISortingCollection<T> {
private sortSettings: SortSettings<T, V>[];
public constructor(iterable: Collection<T>, ...sortSettings: SortSettings<T, V>[]) {
super(iterable);
this.sortSettings = _(sortSettings)
.where(item => !!item.compare || !!item.mapping) //
.toArray();
}
protected materialize(): T[] {
const comparer = new Comparer(this.sortSettings, this.defaultCompare);
return Array.from(this.inner.toArray()).sort(this.sortSettings.length ? (first, second) => comparer.compare(first, second) : undefined);
}
private defaultCompare(first: V, second: V): number {
if(first < second) {
return -1
} else if (second < first) {
return 1
} else {
return 0;
}
}
}
. . Comparer
.
Lodash, js .
----------------------------------------------------
Sort for 1000000:
Sort x 0.80 ops/sec ±3.59% (6 runs sampled)
Lodash sort x 0.97 ops/sec ±27.98% (7 runs sampled)
Native sort x 1.05 ops/sec ±14.71% (7 runs sampled)
SortBy x 0.19 ops/sec ±10.31% (5 runs sampled)
Lodash SortBy x 0.37 ops/sec ±7.21% (5 runs sampled)
Sort after map x 0.47 ops/sec ±8.67% (6 runs sampled)
----------------------------------------------------
Sort for 1000:
Sort x 1,121 ops/sec ±0.77% (85 runs sampled)
Lodash sort x 1,267 ops/sec ±0.77% (89 runs sampled)
Native sort x 1,274 ops/sec ±0.88% (86 runs sampled)
SortBy x 488 ops/sec ±1.45% (80 runs sampled)
Lodash SortBy x 549 ops/sec ±9.60% (70 runs sampled)
Sort after map x 954 ops/sec ±1.50% (83 runs sampled)
----------------------------------------------------
Sort for 10:
Sort x 171,700 ops/sec ±1.38% (85 runs sampled)
Lodash sort x 196,364 ops/sec ±2.01% (80 runs sampled)
Native sort x 250,820 ops/sec ±0.96% (85 runs sampled)
SortBy x 114,064 ops/sec ±0.90% (86 runs sampled)
Lodash SortBy x 86,370 ops/sec ±17.93% (67 runs sampled)
Sort after map x 221,034 ops/sec ±1.31% (87 runs sampled)
----------------------------------------------------
:
± .
Min
实现最小元素搜索聚合器
export class MinAggregator<T> extends ReduceAggregator<T> {
public constructor(collection: ICollection<T>, condition?: CompareCondition<T>) {
super(collection, condition ? (first, second) => this.compare(first, second, condition) : (a, b) => a < b ? a : b)
}
private compare(first: T, second: T, func: CompareCondition<T>): T {
return func(first, second) < 0 ? first : second;
}
}
export class ReduceAggregator<T> extends Aggregator<T> {
public constructor(private collection: ICollection<T>, protected predicate: ReduceCondition<T>){
super();
}
public aggregate(): T {
return this.collection.toArray().reduce((first, second) => this.predicate(first, second))
}
}
他们没想到吗?而且将没有装饰器。
相反,我们将有一个聚合器。
说明
我不确定是否完全需要它,我们只是进行卷积。
----------------------------------------------------
Aggregate for 1000000:
Min x 43.69 ops/sec ±28.48% (65 runs sampled)
Lodash Min x 117 ops/sec ±0.58% (73 runs sampled)
----------------------------------------------------
Aggregate for 1000:
Min x 61,220 ops/sec ±5.10% (87 runs sampled)
Lodash Min x 111,452 ops/sec ±0.72% (90 runs sampled)
----------------------------------------------------
Aggregate for 10:
Min x 3,502,264 ops/sec ±1.36% (86 runs sampled)
Lodash Min x 4,181,189 ops/sec ±1.48% (86 runs sampled)
----------------------------------------------------
Aggregate By for 1000000 disp 50:
Min By x 23.81 ops/sec ±2.02% (42 runs sampled)
Lodash Min By x 42.66 ops/sec ±2.46% (55 runs sampled)
----------------------------------------------------
Aggregate By for 1000 disp 50:
Min By x 43,064 ops/sec ±0.71% (86 runs sampled)
Lodash Min By x 60,212 ops/sec ±0.89% (87 runs sampled)
----------------------------------------------------
Aggregate By for 100 disp 50:
Min By x 351,098 ops/sec ±1.03% (81 runs sampled)
Lodash Min By x 382,302 ops/sec ±1.39% (76 runs sampled)
----------------------------------------------------
Lodash赢了。
结果
我度过了一个有趣而有趣的时光。
我认为,这是我要开发的一个很好的库。
如果有人知道如何减少用于过滤和映射的迭代成本,即:
this.inner.toArray().filter(this.condition);
我会找出答案的!
我乐于批评,我想使代码更好。
谢谢大家的关注。