0.2.10 • Published 1 year ago

type-comparator v0.2.10

Weekly downloads
3
License
MIT
Repository
github
Last release
1 year ago

Type Comparator

Useful comparator functions written on Typescript (But you can use it on your JS project)

Table of Contents

Installation

npm i type-comparator

Usage

Base comparators: asc and desc

asc is simple comparator contains just base comparison logic.

It works well with numbers...

const array = [17, 4, -17, 42, -3, 0];

// [-17, -3, 0, 4, 17, 42]
array.slice().sort(asc); 
// [42, 17, 4, 0, -3, -17]
array.slice().sort(desc); 

And with strings...

const array = ['aaa', 'bax', 'a', 'x', 'ax', 'ab', 'ba', 'bx'];

// ["a", "aaa", "ab", "ax", "ba", "bax", "bx", "x"]
array.slice().sort(asc); 
// ["x", "bx", "bax", "ba", "ax", "ab", "aaa", "a"]
array.slice().sort(desc);

Even with dates...

const array = [new Date(2018, 0, 1), new Date(2017, 0, 1), new Date(2019, 0, 1)];

// [Date(2017, 0, 1), Date(2018, 0, 1), Date(2019, 0, 1)]
array.slice().sort(asc); 
// [Date(2019, 0, 1), Date(2018, 0, 1), Date(2017, 0, 1)]
array.slice().sort(desc);

Actually it works well with everything comparable by > and <.

NOTE Every values which are neither > nor < are equal.

As you can see below, the initial order remains. If you want to sort by value of some item property, take a look on map function.

var array1 = [{a: 1}, {a: 5}];
var array2 = [{a: 5}, {a: 1}];

array1.slice().sort(asc);  // [{a: 1}, {a: 5}]
array2.slice().sort(asc);  // [{a: 5}, {a: 1}]
array1.slice().sort(desc); // [{a: 1}, {a: 5}]
array2.slice().sort(desc); // [{a: 5}, {a: 1}]

Functional way

Function reverse(comparator)

Just swap comparator args.

import { asc, cmp, reverse } from 'type-comparator';

const functionalCmp = reverse(asc);
const array = [17, 4, -17, 42, -3, 0];

// [ 42, 17, 4, 0, -3, -17 ]
array.slice().sort(functionalCmp);  

Function map(mapper, comparator)

Maps each args with mapper and apply comparator.

import { asc, cmp, map } from 'type-comparator';

const mapper = x => x.a;
const comparator = map(mapper, asc);
const array = [{ a: 15 }, { a: 5 }];

// [ { a: 5 }, { a: 15 } ]
array.slice().sort(comparator);

Function condition(conditionFn, comparatorA, comparatorB)

Has following logic:

  • Applies comparatorA, if both args satisfy conditionFn.
  • Applies comparatorB, if both args do not satisfy conditionFn.
  • Returns positive value, if only first arg satisfies conditionFn.
  • Returns negative value, if only second arg satisfies conditionFn.
import { asc, cmp, condition } from 'type-comparator';

const conditionFn = x => x % 2 === 0;
const comparator = condition(conditionFn, asc, desc);
const array = [17, 4, -17, 42, -3, 0];

// [ 17, -3, -17, 0, 4, 42 ]
array.slice().sort(comparator);

Function queue(comparators)

Applies first comparator from comparators.

  • If comparator returns non-zero value, returns it as result.
  • If comparator returns 0, apply next comparator from comparators.
  • If there is no more comparator in comparators list, returns 0.
import { asc, cmp, desc, map, queue } from 'type-comparator';

const comparator = queue([
    map(x => x.name, asc),
    map(x => x.age, desc),
]);
const array = [
    { name: 'Alex', age: 21 },
    { name: 'Jane', age: 19 },
    { name: 'Alex', age: 26 },
];

// [ 
//    { name: 'Alex', age: 26 },
//    { name: 'Alex', age: 21 },
//    { name: 'Jane', age: 19 } 
// ]
array.slice().sort(comparator);

Chaining way

Basic usage

cmp() - just starts chaining. .use(comparator) - applies comparator and terminates chaining.

Note: use() chain can work with any comparator function (not only produced by type-comparator)

import { asc, cmp } from 'type-comparator';

// same as just `asc` function
const comparator1 = cmp().use(asc);

// works like `asc` but just for numbers
const comparator2 = cmp().use((a, b) => a - b); 

// not a lot of sense, but it's possible
const comparator3 = cmp().use(comparator1); 

Chain .reverse()

import { asc, cmp, reverse } from 'type-comparator';

const comparator = cmp().reverse().use(asc);
const array = [17, 4, -17, 42, -3, 0];

// [ 42, 17, 4, 0, -3, -17 ]
array.slice().sort(comparator);

Chain .map(mapper)

import { asc, cmp, map } from 'type-comparator';

const mapper = x => x.a;
const comparator = cmp().map(mapper).use(asc);
const array = [{ a: 15 }, { a: 5 }];

// [ { a: 5 }, { a: 15 } ]
array.slice().sort(comparator);

Chain .if(conditionFn)

Checks conditionFn for each arg.

  • Applies next .then chain, if both args satisfy conditionFn.
  • Applies next .else/.elif chain, if both args do not satisfy conditionFn.
  • Returns positive value, if only first arg satisfies conditionFn.
  • Returns negative value, if only second arg satisfies conditionFn.

Note: After .if() chain, only .then chain is available.

import { asc, cmp } from 'type-comparator';

const conditionFn = x => x % 4 === 0;
const conditionFn2 = x => x % 2 === 0;
const chainingCmp = cmp()
    .if(conditionFn).then(asc)
    .elif(conditionFn2).then(asc)
    .else(asc);
const array = [17, 4, -17, 42, -3, 0];

// [ -17, -3, 17, 42, 0, 4 ]
array.slice().sort(chainingCmp);

Chain .then(comparator)

Applies comparator, if condition from previous .if()chain satisfies for both args.

Note: After .then() chain, only .elif() or .else() chains are available. Note: .then() chain is available only after .if() or .elif() chains.

Chain .elif(conditionFn)

Works same .if() chain.

Note: After .elif() chain, only .then() chain is available. Note: .elif() chain is available only after .then() chain.

Chain .else(comparator)

Applies comparator, if both args do not satisfy comparators from previous .if()/.elif chains.

Note: .else() chain is available only after .then() chain. Note: .else() chain finishes chaining and returns result comparator function.

Chain .use(comparators)

Works same as queue(comparators) and terminates chaining.

import { asc, cmp, desc } from 'type-comparator';

const comparator = cmp().use([
    cmp().map(x => x.name).use(asc),
    cmp().map(x => x.age).use(desc),
]);
const array = [
    { name: 'Alex', age: 21 },
    { name: 'Jane', age: 19 },
    { name: 'Alex', age: 26 },
];

// [ 
//    { name: 'Alex', age: 26 },
//    { name: 'Alex', age: 21 },
//    { name: 'Jane', age: 19 } 
// ]
array.slice().sort(comparator);    

Something more complex?... Ok!

import { asc, cmp, desc } from 'type-comparator';

const comparator = cmp()
    .map(x => x.a)
    .use([
        cmp()
            .map(x => x.b)
            .use(desc),
        cmp()
            .if(x => (x.b + x.c) % 2 === 0)
            .map(x => x.c)
            .use(asc),
    ]);

const array = [
    { a: { b: 1, c: 7 } },
    { a: { b: 1, c: 6 } },
    { a: { b: 1, c: 5 } },
    { a: { b: 1, c: 4 } },
    { a: { b: 1, c: 3 } },
    { a: { b: 3, c: 2 } },
];

// [
//     { a: { b: 3, c: 2 } },
//     { a: { b: 1, c: 4 } },
//     { a: { b: 1, c: 6 } },
//     { a: { b: 1, c: 3 } },
//     { a: { b: 1, c: 5 } },
//     { a: { b: 1, c: 7 } },
// ]
array.slice().sort(comparator);

Q&A

Q: Should reverse(cmp) be equals to reversed array with cmp ?

A: In general, it should not. Array.prototype.reverse just reverse all elements order, regardless its values. When comparator suppose both values are equal, it returns 0. And these elements save original order.

const array = [1, 2, 4];
const comparator = cmp().map(x => x % 2 === 0).use(asc);

// [2, 4, 1]
array.slice().sort(reverse(comparator));

// [4, 2, 1]
array.slice().sort(comparator).reverse();

Support

Please open an issue for support.

Contributing

Please contribute using Github Flow. Create a branch, add commits, and open a pull request.

0.2.10-3

1 year ago

0.2.10-2

1 year ago

0.2.10-1

1 year ago

0.2.10-0

1 year ago

0.2.10

1 year ago

0.2.9

3 years ago

0.2.9-rc.3

3 years ago

0.2.9-rc.2

3 years ago

0.2.9-rc.1

3 years ago

0.2.8

5 years ago

0.2.7

5 years ago

0.2.6

5 years ago

0.2.5

5 years ago

0.2.4

5 years ago

0.2.3

5 years ago

0.2.2

5 years ago

0.2.1

5 years ago

0.2.0

5 years ago

0.1.11

5 years ago

0.1.10

5 years ago

0.1.9

5 years ago

0.1.8

5 years ago

0.1.7

5 years ago

0.1.6

5 years ago

0.1.5

5 years ago

0.1.4

5 years ago

0.1.3

5 years ago

0.1.2

5 years ago

0.1.1

5 years ago

0.0.2

5 years ago

0.0.1

5 years ago