Comparing version
@@ -12,2 +12,3 @@ export default class TreeMap<K, V> extends Map { | ||
private isCompareFn; | ||
private compare; | ||
/** | ||
@@ -21,3 +22,3 @@ * @param compareFn A function that defines the sort order of the keys. | ||
*/ | ||
constructor(iterable?: readonly (readonly [K, V])[] | null, compareFn?: (a: K, b: K) => number); | ||
constructor(iterable?: Iterable<readonly [K, V]> | null, compareFn?: (a: K, b: K) => number); | ||
private _constructor; | ||
@@ -38,2 +39,3 @@ /** | ||
toMap(): Map<K, V>; | ||
reverseKeys(): IterableIterator<K>; | ||
/** | ||
@@ -145,3 +147,15 @@ * Adds or updates entry with the specified value with the specified key in this map. | ||
higherKey(key: K): K | undefined; | ||
/** | ||
* Returns a new TreeMap with entries containing keys less than (or equal to) `key` in this map. | ||
* @param key | ||
* @param include If `true`, split this map including an entry associated with `key`. Default is `true`. | ||
*/ | ||
splitLower(key: K, include?: boolean): TreeMap<K, V>; | ||
/** | ||
* Returns a new TreeMap with entries containing keys greater than (or equal to) `key` in this map. | ||
* @param key | ||
* @param include If `true`, split this map including an entry associated with `key`. Default is `true`. | ||
*/ | ||
splitHigher(key: K, include?: boolean): TreeMap<K, V>; | ||
forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void; | ||
} |
@@ -36,11 +36,9 @@ "use strict"; | ||
this.specifiedCompareFn = false; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
this.isIterable = (value) => { | ||
if (!Array.isArray(value)) { | ||
if (value == null) { | ||
return false; | ||
} | ||
for (const entry of value) { | ||
if (!Array.isArray(entry) || entry.length !== 2) { | ||
return false; | ||
} | ||
const itr = value; | ||
if (itr[Symbol.iterator] == null) { | ||
return false; | ||
} | ||
@@ -64,6 +62,15 @@ return true; | ||
} | ||
// if (reverse) { | ||
// this.reverseOrder = reverse | ||
// } | ||
} | ||
// private reverseOrder: boolean = false | ||
get comparator() { | ||
return this.compareFn; | ||
} | ||
compare(a, b) { | ||
const val = Math.sign(this.compareFn(a, b)); | ||
// return this.reverseOrder ? -val : val | ||
return val; | ||
} | ||
_constructor(iterable, compareFn) { | ||
@@ -105,2 +112,6 @@ this.compareFn = compareFn == null ? comparators.none : compareFn; | ||
} | ||
reverseKeys() { | ||
const keys = [...this.sortedKeys].reverse(); | ||
return keys.values(); | ||
} | ||
/** | ||
@@ -141,3 +152,3 @@ * Adds or updates entry with the specified value with the specified key in this map. | ||
if (super.delete(key)) { | ||
this.sortedKeys = this.sortedKeys.filter(existKey => this.compareFn(existKey, key) !== 0); | ||
this.sortedKeys = this.sortedKeys.filter(existKey => this.compare(existKey, key) !== 0); | ||
return true; | ||
@@ -246,3 +257,3 @@ } | ||
floorKey(key) { | ||
const filtered = this.sortedKeys.filter(existKey => this.compareFn(existKey, key) <= 0); | ||
const filtered = this.sortedKeys.filter(existKey => this.compare(existKey, key) <= 0); | ||
return filtered.reverse()[0]; | ||
@@ -268,3 +279,3 @@ } | ||
ceilingKey(key) { | ||
const filtered = this.sortedKeys.filter(existKey => this.compareFn(existKey, key) >= 0); | ||
const filtered = this.sortedKeys.filter(existKey => this.compare(existKey, key) >= 0); | ||
return filtered[0]; | ||
@@ -290,3 +301,3 @@ } | ||
lowerKey(key) { | ||
const filtered = this.sortedKeys.filter(existKey => this.compareFn(existKey, key) < 0); | ||
const filtered = this.sortedKeys.filter(existKey => this.compare(existKey, key) < 0); | ||
return filtered.reverse()[0]; | ||
@@ -312,5 +323,29 @@ } | ||
higherKey(key) { | ||
const filtered = this.sortedKeys.filter(existKey => this.compareFn(existKey, key) > 0); | ||
const filtered = this.sortedKeys.filter(existKey => this.compare(existKey, key) > 0); | ||
return filtered[0]; | ||
} | ||
/** | ||
* Returns a new TreeMap with entries containing keys less than (or equal to) `key` in this map. | ||
* @param key | ||
* @param include If `true`, split this map including an entry associated with `key`. Default is `true`. | ||
*/ | ||
splitLower(key, include = true) { | ||
const entries = Array.from(this.entries()).filter(e => { | ||
const than = this.compare(e[0], key) < 0; | ||
return include ? than || this.compare(e[0], key) === 0 : than; | ||
}); | ||
return new TreeMap(entries, this.compareFn); | ||
} | ||
/** | ||
* Returns a new TreeMap with entries containing keys greater than (or equal to) `key` in this map. | ||
* @param key | ||
* @param include If `true`, split this map including an entry associated with `key`. Default is `true`. | ||
*/ | ||
splitHigher(key, include = true) { | ||
const entries = Array.from(this.entries()).filter(e => { | ||
const than = this.compare(e[0], key) > 0; | ||
return include ? than || this.compare(e[0], key) === 0 : than; | ||
}); | ||
return new TreeMap(entries, this.compareFn); | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
@@ -317,0 +352,0 @@ forEach(callbackfn, thisArg) { |
{ | ||
"name": "ts-treemap", | ||
"version": "0.0.5", | ||
"version": "1.0.0", | ||
"description": "a TypeScript implementation of TreeMap", | ||
@@ -5,0 +5,0 @@ "main": "dist/TreeMap.js", |
@@ -1,2 +0,2 @@ | ||
[🇯🇵](https://github.com/yuyasvx/ts-treemap/blob/master/README.md)[🇺🇸](https://github.com/yuyasvx/ts-treemap/blob/master/README-en.md) | ||
[🇯🇵 日本語はここ](https://github.com/yuyasvx/ts-treemap/blob/master/README.md) | ||
@@ -10,5 +10,5 @@ # ts-treemap | ||
ES2015 から追加された“Map”オブジェクトをベースに、Java でお馴染みの [TreeMap](https://docs.oracle.com/javase/jp/8/docs/api/java/util/TreeMap.html) の一部機能を TypeScript で使うことが出来ます。 | ||
You can use some features of [TreeMap](https://docs.oracle.com/javase/8/docs/api/java/util/TreeMap.html) in Java with TypeScript. | ||
# インストール | ||
# Installation | ||
@@ -19,8 +19,6 @@ ``` | ||
# 使う | ||
# Usage | ||
ES2015 の Map と同じ要領で使うことが出来ます。 | ||
## Create New TreeMap and Add Entries | ||
## Map の作成とエントリの追加 | ||
```typescript | ||
@@ -35,5 +33,8 @@ import TreeMap from 'ts-treemap' | ||
treeMap.set(0, 'ghi') | ||
// you can also create new TreeMap with iterable | ||
const treeMap2 = new TreeMap<number, string>([[1, 'foo'], [2, 'bar']]) | ||
``` | ||
## エントリの取得 | ||
## Get Entry from TreeMap | ||
@@ -52,3 +53,3 @@ ```typescript | ||
## Map のコピー | ||
## Duplicate a Map | ||
@@ -67,12 +68,10 @@ ```typescript | ||
# 注意! | ||
# Note | ||
キーをソートするためには、比較を行うための関数を定義する必要があります。TreeMap は内部で比較関数を持っており、キーを追加するたびに、比較関数によって自動でキーをソートします。 | ||
To sort the keys, you need to define a function to compare keys in the map. Once TreeMap is constructed with comparator function, the keys are sorted by this function each time an entry is added. | ||
比較関数は、Array.prototype.sort()で用いられる[比較関数](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#説明)に準拠しています。 | ||
The comparator function conforms to the [compare function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#Description) used in `Array.prototype.sort()`. | ||
キーの型が`number`, `string`, `Date`のどれかに該当する場合は、デフォルトで用意されている関数で比較を行うので、比較関数を定義する必要はありません。(ご自身で定義することも出来ます) | ||
You don’t have to define the compare function if the type of the key is `number`, `string` or `Date`. Otherwise, when you construct a new TreeMap without supplying a compare function and add the first entry, an `Error` will be thrown. | ||
キーの型が上記のいずれにも該当しない場合、比較関数を与えずに TreeMap を生成してから**1 つ目のエントリを追加した時にエラーが発生します。** | ||
**✅ Do:** | ||
@@ -96,2 +95,4 @@ | ||
objectMap.set(Day('2019-01-01'), 'foo') // OK | ||
const objectMap2 = new TreeMap<Day.Dayjs, string>([[Day('2019-01-01'), 'foo']], (a, b) => a.unix() - b.unix()) | ||
``` | ||
@@ -98,0 +99,0 @@ |
@@ -46,2 +46,4 @@ /* eslint-disable no-dupe-class-members */ | ||
// private reverseOrder: boolean = false | ||
get comparator(): (a: K, b: K) => number { | ||
@@ -51,11 +53,9 @@ return this.compareFn | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
private isIterable = (value: any): value is [K, V][] => { | ||
if (!Array.isArray(value)) { | ||
private isIterable = (value: unknown): value is Iterable<readonly [K, V]> => { | ||
if (value == null) { | ||
return false | ||
} | ||
for (const entry of value) { | ||
if (!Array.isArray(entry) || entry.length !== 2) { | ||
return false | ||
} | ||
const itr = value as Iterable<readonly [K, V]> | ||
if (itr[Symbol.iterator] == null) { | ||
return false | ||
} | ||
@@ -70,2 +70,8 @@ return true | ||
private compare(a: K, b: K): number { | ||
const val = Math.sign(this.compareFn(a, b)) | ||
// return this.reverseOrder ? -val : val | ||
return val | ||
} | ||
/** | ||
@@ -79,3 +85,3 @@ * @param compareFn A function that defines the sort order of the keys. | ||
*/ | ||
constructor(iterable?: readonly (readonly [K, V])[] | null, compareFn?: (a: K, b: K) => number) | ||
constructor(iterable?: Iterable<readonly [K, V]> | null, compareFn?: (a: K, b: K) => number) | ||
constructor(iterableOrCompareFn?: unknown, compareFn?: (a: K, b: K) => number) { | ||
@@ -94,5 +100,8 @@ super() | ||
} | ||
// if (reverse) { | ||
// this.reverseOrder = reverse | ||
// } | ||
} | ||
private _constructor(iterable?: readonly (readonly [K, V])[] | null, compareFn?: (a: K, b: K) => number): void { | ||
private _constructor(iterable?: Iterable<readonly [K, V]> | null, compareFn?: (a: K, b: K) => number): void { | ||
this.compareFn = compareFn == null ? comparators.none : compareFn | ||
@@ -137,2 +146,7 @@ this.specifiedCompareFn = compareFn != null | ||
public reverseKeys(): IterableIterator<K> { | ||
const keys = [...this.sortedKeys].reverse() | ||
return keys.values() | ||
} | ||
/** | ||
@@ -177,3 +191,3 @@ * Adds or updates entry with the specified value with the specified key in this map. | ||
if (super.delete(key)) { | ||
this.sortedKeys = this.sortedKeys.filter(existKey => this.compareFn(existKey, key) !== 0) | ||
this.sortedKeys = this.sortedKeys.filter(existKey => this.compare(existKey, key) !== 0) | ||
return true | ||
@@ -294,3 +308,3 @@ } | ||
public floorKey(key: K): K | undefined { | ||
const filtered = this.sortedKeys.filter(existKey => this.compareFn(existKey, key) <= 0) | ||
const filtered = this.sortedKeys.filter(existKey => this.compare(existKey, key) <= 0) | ||
return filtered.reverse()[0] | ||
@@ -318,3 +332,3 @@ } | ||
public ceilingKey(key: K): K | undefined { | ||
const filtered = this.sortedKeys.filter(existKey => this.compareFn(existKey, key) >= 0) | ||
const filtered = this.sortedKeys.filter(existKey => this.compare(existKey, key) >= 0) | ||
return filtered[0] | ||
@@ -342,3 +356,3 @@ } | ||
public lowerKey(key: K): K | undefined { | ||
const filtered = this.sortedKeys.filter(existKey => this.compareFn(existKey, key) < 0) | ||
const filtered = this.sortedKeys.filter(existKey => this.compare(existKey, key) < 0) | ||
return filtered.reverse()[0] | ||
@@ -366,6 +380,32 @@ } | ||
public higherKey(key: K): K | undefined { | ||
const filtered = this.sortedKeys.filter(existKey => this.compareFn(existKey, key) > 0) | ||
const filtered = this.sortedKeys.filter(existKey => this.compare(existKey, key) > 0) | ||
return filtered[0] | ||
} | ||
/** | ||
* Returns a new TreeMap with entries containing keys less than (or equal to) `key` in this map. | ||
* @param key | ||
* @param include If `true`, split this map including an entry associated with `key`. Default is `true`. | ||
*/ | ||
public splitLower(key: K, include: boolean = true): TreeMap<K, V> { | ||
const entries = Array.from(this.entries()).filter(e => { | ||
const than = this.compare(e[0], key) < 0 | ||
return include ? than || this.compare(e[0], key) === 0 : than | ||
}) | ||
return new TreeMap(entries, this.compareFn) | ||
} | ||
/** | ||
* Returns a new TreeMap with entries containing keys greater than (or equal to) `key` in this map. | ||
* @param key | ||
* @param include If `true`, split this map including an entry associated with `key`. Default is `true`. | ||
*/ | ||
public splitHigher(key: K, include: boolean = true): TreeMap<K, V> { | ||
const entries = Array.from(this.entries()).filter(e => { | ||
const than = this.compare(e[0], key) > 0 | ||
return include ? than || this.compare(e[0], key) === 0 : than | ||
}) | ||
return new TreeMap(entries, this.compareFn) | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
@@ -372,0 +412,0 @@ public forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void { |
@@ -46,5 +46,15 @@ import TreeMap from '../../src/TreeMap' | ||
expect(map6.size).toBe(0) | ||
const plainMap = new Map([[2, 'b'], [1, 'a']]) | ||
const map7 = new TreeMap(plainMap.entries()) | ||
expect(Array.from(map7.entries())).toStrictEqual([[1, 'a'], [2, 'b']]) | ||
}) | ||
it('add', () => { | ||
it('reverse', () => { | ||
const keys = getTreeMap().reverseKeys() | ||
expect(Array.from(keys)).toStrictEqual([20, 15, 10, 5, 0]) | ||
}) | ||
it('set', () => { | ||
const treeMap = getTreeMap() | ||
@@ -228,2 +238,18 @@ | ||
it('split', () => { | ||
const lowerMap = getTreeMap().splitLower(10) | ||
expect(Array.from(lowerMap.keys())).toStrictEqual([0, 5, 10]) | ||
const higherMap = getTreeMap().splitHigher(10) | ||
expect(Array.from(higherMap.keys())).toStrictEqual([10, 15, 20]) | ||
}) | ||
it('split include:false', () => { | ||
const lowerMap = getTreeMap().splitLower(10, false) | ||
expect(Array.from(lowerMap.keys())).toStrictEqual([0, 5]) | ||
const higherMap = getTreeMap().splitHigher(10, false) | ||
expect(Array.from(higherMap.keys())).toStrictEqual([15, 20]) | ||
}) | ||
it('forEach', () => { | ||
@@ -230,0 +256,0 @@ const treeMap = getTreeMap() |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
59798
9.61%1206
9.34%1
-50%104
0.97%