Skip to content

Commit

Permalink
improvement(OrderedList): ToList function now returns an actual List<…
Browse files Browse the repository at this point in the history
…T> from an ordered list
  • Loading branch information
kutyel committed May 16, 2023
1 parent 2cf2e0e commit efd83df
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 34 deletions.
41 changes: 37 additions & 4 deletions __tests__/list.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,39 @@ test('OrderByDescending', t => {
.ToArray(),
[6, 5, 4, 3, 2, 1]
)

// sorting with custom comparer function
const items = new List([
new Product({ Name: 'Edward', Code: 21 }),
new Product({ Name: 'Sharpe', Code: 37 }),
new Product({ Name: 'And', Code: 45 }),
new Product({ Name: 'The', Code: -12 }),
new Product({ Name: 'Magnetic', Code: 13 }),
new Product({ Name: 'Zeros', Code: 37 })
])

const nameComparerFn = (a: IProduct, b: IProduct) => {
const nameA = a.Name.toUpperCase() // ignore upper and lowercase
const nameB = b.Name.toUpperCase() // ignore upper and lowercase
if (nameA < nameB) {
return -1
}
if (nameA > nameB) {
return 1
}

// names must be equal
return 0
}
const ordered = new List([
new Product({ Name: 'And', Code: 45 }),
new Product({ Name: 'Edward', Code: 21 }),
new Product({ Name: 'Magnetic', Code: 13 }),
new Product({ Name: 'Sharpe', Code: 37 }),
new Product({ Name: 'The', Code: -12 }),
new Product({ Name: 'Zeros', Code: 37 })
])
t.deepEqual(items.OrderByDescending(a => a, nameComparerFn).ToList(), ordered)
})

test('ThenBy', t => {
Expand Down Expand Up @@ -1074,15 +1107,15 @@ test('ToLookup', t => {
t.deepEqual(lookup, result)
})

test.skip('Union', t => {
test('Union', t => {
const ints1 = new List<number>([5, 3, 9, 7, 5, 9, 3, 7])
const ints2 = new List<number>([8, 3, 6, 4, 4, 9, 1, 0])
t.deepEqual(ints1.Union(ints2).ToArray(), [5, 3, 9, 7, 8, 6, 4, 1, 0])

const result = [
{ Name: 'apple', Code: 9 },
{ Name: 'orange', Code: 4 },
{ Name: 'lemon', Code: 12 }
new Product({ Name: 'apple', Code: 9 }),
new Product({ Name: 'orange', Code: 4 }),
new Product({ Name: 'lemon', Code: 12 })
]
const store1 = new List<Product>([
new Product({ Name: 'apple', Code: 9 }),
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"types": "dist/src/index.d.ts",
"scripts": {
"build": "tsc",
"check-coverage": "nyc check-coverage --statements 99 --branches 97 --functions 98 --lines 99",
"check-coverage": "nyc check-coverage --statements 100 --branches 98 --functions 99 --lines 100",
"commit": "git-cz",
"cover": "nyc --require ts-node/register --reporter=lcov npm t",
"docs": "typedoc --out ../docs/ src/index.ts -m commonjs -t ES6",
Expand Down
94 changes: 65 additions & 29 deletions src/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,29 @@ import { composeComparers, negate, isObj, equal, keyComparer } from './helpers'
type PredicateType<T> = (value?: T, index?: number, list?: T[]) => boolean

class List<T> {

protected _elements: T[]
protected _elements: T[];

/**
* Make the List iterable and Spreadable
*/
*[Symbol.iterator]() {
for (let element of this._elements) {
yield element;
yield element
}
}

/**
* property represents the Object name
*/
get [Symbol.toStringTag]() {
return 'List'; // Expected output: "[object List]"
return 'List' // Expected output: "[object List]"
}

/**
* Defaults the elements of the list
*/
constructor(elements: T[] = []) {
this._elements = [...elements];
this._elements = [...elements]
}

/**
Expand Down Expand Up @@ -60,7 +59,10 @@ class List<T> {
/**
* Applies an accumulator function over a sequence.
*/
public Aggregate<U>(accumulator: (accum: U, value?: T, index?: number, list?: T[]) => any, initialValue?: U): any {
public Aggregate<U>(
accumulator: (accum: U, value?: T, index?: number, list?: T[]) => any,
initialValue?: U
): any {
return this._elements.reduce(accumulator, initialValue)
}

Expand All @@ -84,7 +86,9 @@ class List<T> {
* Computes the average of a sequence of number values that are obtained by invoking
* a transform function on each element of the input sequence.
*/
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)
}

Expand Down Expand Up @@ -120,19 +124,15 @@ class List<T> {
* Returns the number of elements in a sequence.
*/
public Count(predicate?: PredicateType<T>): number {
return predicate
? this.Where(predicate).Count()
: this._elements.length
return predicate ? this.Where(predicate).Count() : this._elements.length
}

/**
* Returns the elements of the specified sequence or the type parameter's default value
* in a singleton collection if the sequence is empty.
*/
public DefaultIfEmpty(defaultValue?: T): List<T> {
return this.Count()
? this
: new List<T>([defaultValue])
return this.Count() ? this : new List<T>([defaultValue])
}

/**
Expand Down Expand Up @@ -165,7 +165,9 @@ class List<T> {
if (index < this.Count() && index >= 0) {
return this._elements[index]
}
throw new Error('ArgumentOutOfRangeException: index is less than 0 or greater than or equal to the number of elements in source.')
throw new Error(
'ArgumentOutOfRangeException: index is less than 0 or greater than or equal to the number of elements in source.'
)
}

/**
Expand Down Expand Up @@ -279,7 +281,9 @@ class List<T> {
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)))
return this.SelectMany(x =>
list.Where(y => key2(y) === key1(x)).Select(z => result(x, z))
)
}

/**
Expand All @@ -304,15 +308,19 @@ class List<T> {
/**
* Returns the maximum value in a generic sequence.
*/
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))
}

/**
* Returns the minimum value in a generic sequence.
*/
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))
}
Expand All @@ -333,7 +341,7 @@ class List<T> {
typeName = typeof true
break
case Function:
typeName = typeof function () { } // tslint:disable-line no-empty
typeName = typeof function() {} // tslint:disable-line no-empty
break
default:
typeName = null
Expand All @@ -347,15 +355,21 @@ class List<T> {
/**
* Sorts the elements of a sequence in ascending order according to a key.
*/
public OrderBy(keySelector: (key: T) => any, comparer = keyComparer(keySelector, false)): List<T> {
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)
}

/**
* Sorts the elements of a sequence in descending order according to a key.
*/
public OrderByDescending(keySelector: (key: T) => any, comparer = keyComparer(keySelector, true)): List<T> {
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)
}
Expand Down Expand Up @@ -407,14 +421,18 @@ class List<T> {
/**
* Projects each element of a sequence into a new form.
*/
public Select<TOut>(selector: (element: T, index: number) => TOut): List<TOut> {
public Select<TOut>(
selector: (element: T, index: number) => TOut
): List<TOut> {
return new List<TOut>(this._elements.map(selector))
}

/**
* Projects each element of a sequence to a List<any> and flattens the resulting sequences into one sequence.
*/
public SelectMany<TOut extends List<any>>(selector: (element: T, index: number) => TOut): TOut {
public SelectMany<TOut extends List<any>>(
selector: (element: T, index: number) => TOut
): TOut {
return this.Aggregate(
(ac, _, i) => (
ac.AddRange(
Expand Down Expand Up @@ -450,9 +468,7 @@ class List<T> {
* this method throws an exception if there is more than one element in the sequence.
*/
public SingleOrDefault(predicate?: PredicateType<T>): T {
return this.Count(predicate)
? this.Single(predicate)
: undefined
return this.Count(predicate) ? this.Single(predicate) : undefined
}

/**
Expand Down Expand Up @@ -482,7 +498,9 @@ class List<T> {
* Computes the sum of the sequence of number values that are obtained by invoking
* a transform function on each element of the input sequence.
*/
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)
Expand Down Expand Up @@ -521,7 +539,10 @@ class List<T> {
/**
* Creates a Dictionary<TKey, TValue> from a List<T> according to a specified key selector function.
*/
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)
Expand All @@ -547,7 +568,10 @@ class List<T> {
/**
* Creates a Lookup<TKey, TElement> from an IEnumerable<T> according to specified key selector and element selector functions.
*/
public ToLookup<TResult>(keySelector: (key: T) => string | number, elementSelector: (element: T) => TResult): { [key: string]: TResult[] } {
public ToLookup<TResult>(
keySelector: (key: T) => string | number,
elementSelector: (element: T) => TResult
): { [key: string]: TResult[] } {
return this.GroupBy(keySelector, elementSelector)
}

Expand All @@ -568,7 +592,10 @@ class List<T> {
/**
* Applies a specified function to the corresponding elements of two sequences, producing a sequence of the results.
*/
public Zip<U, TOut>(list: List<U>, result: (first: T, second: U) => TOut): List<TOut> {
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)))
Expand All @@ -587,6 +614,15 @@ class OrderedList<T> extends List<T> {
this._elements.sort(this._comparer)
}

/**
* Allows you to get the parent List out of the OrderedList
* @override
* @returns and ordered list turned into a regular List<T>
*/
public ToList(): List<T> {
return new List<T>(this._elements)
}

/**
* Performs a subsequent ordering of the elements in a sequence in ascending order according to a key.
* @override
Expand Down

0 comments on commit efd83df

Please sign in to comment.