Skip to content

Commit

Permalink
use more sequences
Browse files Browse the repository at this point in the history
  • Loading branch information
sgratzl committed Nov 23, 2018
1 parent b82ab05 commit 49154f3
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 115 deletions.
175 changes: 94 additions & 81 deletions src/internal/interable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ export interface ISequence<T> extends Iterable<T> {
filter(callback: (v: T, i: number) => boolean): ISequence<T>;
map<U>(callback: (v: T, i: number) => U): ISequence<U>;
forEach(callback: (v: T, i: number) => void): void;

some(callback: (v: T, i: number) => boolean): boolean;
every(callback: (v: T, i: number) => boolean): boolean;
reduce<U>(callback: (acc: U, v: T, i: number) => U, initial: U): U;
}

export function isSeqEmpty(seq: ISequence<any>) {
return seq.every(() => false); // more efficent than counting length
}

class LazyFilter<T> implements ISequence<T> {
Expand Down Expand Up @@ -32,41 +40,77 @@ class LazyFilter<T> implements ISequence<T> {
}

forEach(callback: (v: T, i: number) => void) {
let i = 0;
this.it.forEach((v) => {
let valid = 0;
this.it.forEach((v, i) => {
for (const f of this.filters) {
if (!f(v, i)) {
return;
}
}
callback(v, i++);
callback(v, valid++);
});
}

[Symbol.iterator]() {
const it = this.it[Symbol.iterator]();
const next = () => {
let v = it.next();
let i = 0;
let i = -1;
outer: while (!v.done) {
i++;
for (const f of this.filters) {
if (f(v.value, i)) {
continue;
}
// invalid go to next
v = it.next();
i++;
continue outer;
}
}
return v;
};
return { next };
}

some(callback: (v: T, i: number) => boolean) {
let valid = 0;
return this.it.some((v, i) => {
for (const f of this.filters) {
if (!f(v, i)) {
return false;
}
}
return callback(v, valid++);
});
}

every(callback: (v: T, i: number) => boolean) {
let valid = 0;
return this.it.every((v, i) => {
for (const f of this.filters) {
if (!f(v, i)) {
return false;
}
}
return callback(v, valid++);
});
}

reduce<U>(callback: (acc: U, v: T, i: number) => U, initial: U) {
let valid = 0;
return this.it.reduce((acc, v, i) => {
for (const f of this.filters) {
if (!f(v, i)) {
return acc;
}
}
return callback(acc, v, valid++);
}, initial);
}
}

class LazyMap1<T1, T2> implements ISequence<T2> {
constructor(private readonly it: ISequence<T1>, private readonly map12: (v: T1, i: number) => T2) {
abstract class ALazyMap<T, T2> implements ISequence<T2> {
constructor(protected readonly it: ISequence<T>) {

}

Expand All @@ -78,13 +122,13 @@ class LazyMap1<T1, T2> implements ISequence<T2> {
return new LazyFilter(this, [callback]);
}

map<U>(callback: (v: T2, i: number) => U): ISequence<U> {
return new LazyMap2(this.it, this.map12, callback);
}
abstract map<U>(callback: (v: T2, i: number) => U): ISequence<U>;
protected abstract mapV(v: T, i: number): T2;


forEach(callback: (v: T2, i: number) => void) {
this.it.forEach((v, i) => {
callback(this.map12(v, i), i);
callback(this.mapV(v, i), i);
});
}

Expand All @@ -99,7 +143,7 @@ class LazyMap1<T1, T2> implements ISequence<T2> {
done: true
};
}
const value = this.map12(v.value, ++i);
const value = this.mapV(v.value, ++i);
i++;
return {
value,
Expand All @@ -108,97 +152,57 @@ class LazyMap1<T1, T2> implements ISequence<T2> {
};
return { next };
}
}

class LazyMap2<T, T2, T3> implements ISequence<T3> {
constructor(private readonly it: ISequence<T>, private readonly map12: (v: T, i: number) => T2, private readonly map23: (v: T2, i: number) => T3) {

some(callback: (v: T2, i: number) => boolean) {
return this.it.some((v, i) => callback(this.mapV(v, i), i));
}

get length() {
return this.it.length;
every(callback: (v: T2, i: number) => boolean) {
return this.it.every((v, i) => callback(this.mapV(v, i), i));
}

filter(callback: (v: T3, i: number) => boolean): ISequence<T3> {
return new LazyFilter(this, [callback]);
}

map<U>(callback: (v: T3, i: number) => U): ISequence<U> {
return new LazyMap3(this.it, this.map12, this.map23, callback);
reduce<U>(callback: (acc: U, v: T2, i: number) => U, initial: U) {
return this.it.reduce((acc, v, i) => callback(acc, this.mapV(v, i), i), initial);
}
}

forEach(callback: (v: T3, i: number) => void) {
this.it.forEach((v, i) => {
callback(this.map23(this.map12(v, i), i), i);
});
class LazyMap1<T1, T2> extends ALazyMap<T1, T2> implements ISequence<T2> {
constructor(it: ISequence<T1>, protected readonly mapV: (v: T1, i: number) => T2) {
super(it);
}

[Symbol.iterator]() {
const it = this.it[Symbol.iterator]();
let i = 0;
const next = () => {
const v = it.next();
if (v.done) {
return {
value: <T3><any>undefined,
done: true
};
}
const value = this.map23(this.map12(v.value, i), i);
i++;
return {
value,
done: false
};
};
return { next };
map<U>(callback: (v: T2, i: number) => U): ISequence<U> {
return new LazyMap2(this.it, this.mapV, callback);
}
}

class LazyMap2<T1, T2, T3> extends ALazyMap<T1, T3> implements ISequence<T3> {
constructor(it: ISequence<T1>, private readonly map12: (v: T1, i: number) => T2, private readonly map23: (v: T2, i: number) => T3) {
super(it);
}

class LazyMap3<T1, T2, T3, T4> implements ISequence<T4> {
constructor(private readonly it: ISequence<T1>, private readonly map12: (v: T1, i: number) => T2, private readonly map23: (v: T2, i: number) => T3, private readonly map34: (v: T3, i: number) => T4) {

map<U>(callback: (v: T3, i: number) => U): ISequence<U> {
return new LazyMap3(this.it, this.map12, this.map23, callback);
}

get length() {
return this.it.length;
protected mapV(v: T1, i: number) {
return this.map23(this.map12(v, i), i);
}
}

filter(callback: (v: T4, i: number) => boolean): ISequence<T4> {
return new LazyFilter(this, [callback]);

class LazyMap3<T1, T2, T3, T4> extends ALazyMap<T1, T4> implements ISequence<T4> {
constructor(it: ISequence<T1>, private readonly map12: (v: T1, i: number) => T2, private readonly map23: (v: T2, i: number) => T3, private readonly map34: (v: T3, i: number) => T4) {
super(it);
}

map<U>(callback: (v: T4, i: number) => U): ISequence<U> {
const map1U = (v: T1, i: number) => callback(this.map34(this.map23(this.map12(v, i), i), i), i);
return new LazyMap1(this.it, map1U);
}

forEach(callback: (v: T4, i: number) => void) {
this.it.forEach((v, i) => {
callback(this.map34(this.map23(this.map12(v, i), i), i), i);
});
}

[Symbol.iterator]() {
const it = this.it[Symbol.iterator]();
let i = 0;
const next = () => {
const v = it.next();
if (v.done) {
return {
value: <T4><any>undefined,
done: true
};
}
i++;
const value = this.map34(this.map23(this.map12(v.value, i), i), i);
return {
value,
done: false
};
};
return { next };
protected mapV(v: T1, i: number) {
return this.map34(this.map23(this.map12(v, i), i), i);
}
}

Expand All @@ -213,7 +217,7 @@ export function lazySeq<T>(it: Iterable<T>): ISequence<T> {
} else {
v = Array.from(it);
}
return v;
return v!;
};

const r: any = {
Expand All @@ -231,7 +235,16 @@ export function lazySeq<T>(it: Iterable<T>): ISequence<T> {
for (const v of asArr()) {
cb(v, i++);
}
}
},
some(callback: (v: T, i: number) => boolean) {
return asArr().some(callback);
},
every(callback: (v: T, i: number) => boolean) {
return asArr().every(callback);
},
reduce<U>(callback: (acc: U, v: T, i: number) => U, initial: U) {
return asArr().reduce(callback, initial);
},
};

Object.defineProperty(r, 'length', {
Expand Down
19 changes: 8 additions & 11 deletions src/model/DateColumn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import {widthChanged, labelChanged, metaDataChanged, dirty, dirtyHeader, dirtyVa
import {IEventListener} from '../internal/AEventDispatcher';
import Column from './Column';
import {IDateFilter, IDateDesc, noDateFilter, isDateIncluded, isDummyDateFilter, isEqualDateFilter, IDateGrouper, restoreDateFilter, IDateColumn, toDateGroup, isDefaultDateGrouper, defaultDateGrouper} from './IDateColumn';
import {median} from 'd3-array';
import {defaultGroup} from './Group';
import {equal} from '../internal/utils';
import {ISequence, isSeqEmpty} from '../internal/interable';


export declare type IDateColumnDesc = IValueColumnDesc<Date> & IDateDesc;
Expand Down Expand Up @@ -193,23 +193,20 @@ export default class DateColumn extends ValueColumn<Date> implements IDateColumn
/**
* @internal
*/
export function choose(rows: IDataRow[], grouper: IDateGrouper | null, col: IDateColumn): { value: number | null, name: string } {
const vs = <Date[]>rows.map((d) => col.getDate(d)).filter((d) => d instanceof Date);
if (vs.length === 0) {
export function choose(rows: ISequence<IDataRow>, grouper: IDateGrouper | null, col: IDateColumn): { value: number | null, name: string } {
const vs = <ISequence<Date>>rows.map((d) => col.getDate(d)).filter((d) => d instanceof Date);
if (isSeqEmpty(vs)) {
return {value: null, name: ''};
}
const median = trueMedian(vs, (d) => d.getTime())!;
const median = trueMedian(vs.map((d) => d.getTime()))!;
if (!grouper) {
return {value: median, name: (new Date(median)).toString()};
}
return toDateGroup(grouper, new Date(median));
}

function trueMedian(dates: Date[], acc: (d: Date) => number) {
if (dates.length % 2 === 1) {
return median(dates, acc);
}
function trueMedian(dates: ISequence<number>) {
// to avoid interpolating between the centers do it manually
const s = dates.slice().sort((a, b) => a.getTime() - b.getTime());
return s[Math.floor(s.length / 2)].getTime();
const s = Uint32Array.from(dates).sort();
return s[Math.floor(s.length / 2)];
}
24 changes: 24 additions & 0 deletions src/model/Group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,27 @@ export function mapIndices<T>(arr: IndicesArray, callback: (value: number, i: nu
}
return r;
}


/**
* @internal
*/
export function filterIndices(arr: IndicesArray, callback: (value: number, i: number) => boolean): number[] {
const r: number[] = [];
for (let i = 0; i < arr.length; ++i) {
if (callback(arr[i], i)) {
r.push(arr[i]);
}
}
return r;
}


/**
* @internal
*/
export function forEachIndices(arr: IndicesArray, callback: (value: number, i: number) => void) {
for (let i = 0; i < arr.length; ++i) {
callback(arr[i], i);
}
}
Loading

0 comments on commit 49154f3

Please sign in to comment.