Code Monkey home page Code Monkey logo

sort-es's Introduction

sort-es

License: MIT Build Version Known Vulnerabilities GitHub last commit (branch) npm npm total codecov

Blazing fast, tree-shakeable, type-safe, modern utility library to sort any type of array

Getting started

installation

The library is available as a npm package. To install the package, run:

npm install sort-es
# or
yarn add sort-es

Start using:

import {byString} from 'sort-es'

const unsorted = ["xxx", "bbbb", "zzz", "cccc", "aaa"];
const sorted = unsorted.sort(byString());

console.log(sorted); //(5) ["aaa", "bbbb", "cccc", "xxx", "zzz"]

Use directly in the browser

<script src='https://cdn.jsdelivr.net/npm/sort-es/dist/index.umd.js'></script>
<script>
  const unsorted = ["xxx", "bbbb", "zzz", "cccc", "aaa"];
  const sorted = unsorted.sort(sort.byString());

  console.log(sorted); //(5) ["aaa", "bbbb", "cccc", "xxx", "zzz"]
</script>

//or via browser modules

<script type='module'>
  import {byString} from 'https://cdn.jsdelivr.net/npm/sort-es/dist/index.mjs'

  const unsorted = ["xxx", "bbbb", "zzz", "cccc", "aaa"];
  const sorted = unsorted.sort(byString());

  console.log(sorted); //(5) ["aaa", "bbbb", "cccc", "xxx", "zzz"]
</script>

Some mind-blowing example

sort by a single property

//js or ts file
import {byValue, byNumber, byString} from 'sort-es'

const arrayUnsorted = [
  {prop: "xxx", foo: 34},
  {prop: "aaa", foo: 325},
  {prop: "zzz", foo: 15},
  {prop: "ccc", foo: 340},
  {prop: "bbb", foo: 0}
];

//this sort by the foo property ascending
const sortedByFoo = arrayUnsorted.sort(byValue((i) => i.foo, byNumber()));
console.log(sortedByFoo); //(5) [{prop: "bbb", foo : 0}, {prop: "zzz", foo: 15}, .....];

//this sort by the prop property descending
const sortedByProp = arrayUnsorted.sort(byValue((i) => i.prop, byString({desc: true})));
console.log(sortedByProp); //(5) [{prop: "zzz", foo : 15}, {prop: "xxx", foo: 34}, .....];

sort by a multiple property

//js or ts file
import {byNumber, byString, byValues} from "sort-es";

const objsToSort = [
  {id: 2, name: 'teresa'},
  {id: 3, name: 'roberto'},
  {id: 2, name: 'roberto'}
];

//i sort by THEIR NAMES and THEN by their ids
const sortedObject = objsToSort.sort(byValues([
  [(x) => x.name, byString()],
  [(x) => x.id, byNumber()]
]));

console.log(sortedObject); //[{roberto, 2}, {roberto, 3}, {teresa, 2}];

//i sort by THEIR IDS and THEN by their names
const sortedObject2 = objsToSort.sort(byValues([
  [(x) => x.id, byNumber()],
  [(x) => x.name, byString()]
]));
console.log(sortedObject2); //[{roberto, 2}, {teresa, 2}, {roberto, 3}];

//i sort by THEIR IDS and THEN by their names DESCENDING
const sortedObject3 = objsToSort.sort(byValues([
  [(x) => x.id, byNumber()],
  [(x) => x.name, byString({desc: true})],
]));
console.log(sortedObject3); //[{teresa, 2}, {roberto, 2}, {roberto, 3}];

typescript types check

//ts file
import {byValue, byNumber, byString} from 'sort-es'

const objsArray = [{numbProp: 2, stringProp: 'a'}, {numbProp: 3, stringProp: 'f'}];

//Incorrect sort property
const incorrectSortedArray = objsArray.sort(byValue(i => i.numbProp, byString()));
//ts check error : Type 'number' is not assignable to type 'string'.

//Correct sort type
const sortedArray = objsArray.sort(byValue(i => i.numbProp, byNumber()))
//ts check ok

See full Docs

License

MIT © Cosimo chellini

sort-es's People

Contributors

cosimochellini avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

sort-es's Issues

byString depends on locale

IMHO byString should use JavaScript's relational operators rather than a locale-sensitive comparison to avoid surprises where different users see different sort orders. Using a locale-sensitive comparison should be something users can opt into via the options parameter.

I propose adding a "locale" option, where true means to use the current locale, a falsy value means to use the < operator, and a nonempty string means to use a specific locale. As this would be a potentially breaking change for some users, the project's major version number should be increased.

Support discriminator as function in byValues()

in byValue we are able to specify a simple key, or a function that returns the actual value, as discriminator. This allows us to not only sort by first level attributes, but by any deep property in the object.

We loose that options in byValues() where SortableTuple only accepts Tkey as first parameter. Looking at the code

if (Array.isArray(sorter)) {
return (first: T, second: T): number => {
for (const [prop, sortableFn] of sorter) {
if (!sortableFn) continue;
const sortResult = sortableFn(first[prop], second[prop]);
if (sortResult !== 0) return sortResult;
}
return 0;
};
}

i see no reason not to support that. I'm wrong?

Thanks for this little library. Saves us a looot of work.

Nullable values sort order

The current documentation doesn't mention how nulls are sorted on each of the sort functions.

Would it be possible to add a sort option that allows configuration on if nulls should be sorted first or last?

byValues does not guarantee the sort order

Problem

Your documentation says:

The sorter allows you to declare which properties are needed to sort the array, in what order, and with what sortable

And there is an example below:

//i sort by THEIR NAMES and THEN by their ids
const sortedObject = objsToSort.sort(byValues({
    name: byString(),
    id: byNumber()
}));

// -- snip --

//i sort by THEIR IDS and THEN by their names
const sortedObject2 = objsToSort.sort(byValues({
    id: byNumber(),
    name: byString(),
}));

This actually works... but not in all cases. See this code example:

console.log('String keys');

const ARR = [
    {
        id: 1,
        name: 'b',
    },
    {
        id: 2,
        name: 'a',
    },
    {
        id: 3,
        name: 'c',
    },
];

console.log(
    [...ARR].sort(
        byValues({
            id: byNumber(),
            name: byString(),
        }),
    ),
);
console.log(
    [...ARR].sort(
        byValues({
            name: byString(),
            id: byNumber(),
        }),
    ),
);

// Numeric keys - NOT OK!

console.log('\nNumeric keys');

const ARR_NUM = [
    {
        1: 1,
        2: 'b',
    },
    {
        1: 2,
        2: 'a',
    },
    {
        1: 3,
        2: 'c',
    },
];

console.log(
    [...ARR_NUM].sort(
        byValues({
            1: byNumber(),
            2: byString(),
        }),
    ),
);
console.log(
    [...ARR_NUM].sort(
        byValues({
            2: byString(),
            1: byNumber(),
        }),
    ),
);

This code produces this output:

String keys
[ { id: 1, name: 'b' }, { id: 2, name: 'a' }, { id: 3, name: 'c' } ]
[ { id: 2, name: 'a' }, { id: 1, name: 'b' }, { id: 3, name: 'c' } ]

Numeric keys
[ { '1': 1, '2': 'b' }, { '1': 2, '2': 'a' }, { '1': 3, '2': 'c' } ]
[ { '1': 1, '2': 'b' }, { '1': 2, '2': 'a' }, { '1': 3, '2': 'c' } ]

As you can see, in the second case, the sort order has not changed.

Why?..

See this:

Property keys are traversed in the following order:

  • First, the keys that are integer indices (what these are is explained later), in ascending numeric order.
  • Then, all other string keys, in the order in which they were added to the object.
  • Lastly, all symbol keys, in the order in which they were added to the object.

Traversing keys in JavaScript objects does not guarantee the sequence in which these keys were added (in ALL cases). This works for Map, but not for plain objects.

Option to solve the problem

You cannot guarantee the sort order through object keys. Creating a Map for this is too cumbersome. But you can sequentially specify fields for sorting in this form:

[
    { id: 'asdf', 1: 4123, 0: false },
    { id: 'asdf', 1: 1232, 0: true },
    { id: 'asdf', 1: 5515, 0: false },
].sort(byValues(['id', byString()], [1, byNumber()]))

In this case, a list of arguments is passed from tuples [number | string | symbol, sortable].

byDate doesn't handle nullable

When sorting byDate on a column that might contain null, the byDate function throws:

// releasedAt is a nullable ISO date string: string | null 
byValues([
  [(i) => i.releasedAt as string, byDate({ nullable: true, desc })],
])

// Throws: TypeError: Cannot read properties of null (reading 'getTime')

Loving this package. Quick question about byValues vs byValue.

Hi. This is so easy to use, fast, and creates readable code. I'm really enjoying it.

Is there a difference/benefit to one of these approaches?

const weightsAsc = healthData.weights.sort(byValues({ created_at: byDate() }));

vs

const weightsAsc = healthData.weights.sort(byValue((weight) => weight.created_at, byDate()));

Why would I go with the second when the first is more succinct? Thanks!

byNumber()(Infinity, Infinity) returns NaN

Comparing subtracting Infinity or -Infinity from itself produces NaN, which causes byNumber to return NaN. This isn't a problem for sorting, because Array.prototype.sort treats NaN as 0, but it probably violates user expectations. It can be fixed by adding "|| 0" after the subtractions in byNumber.

Nullable's

Thank you for this library, which seems to cover most of what I need.

I am wondering about dealign with null's. SortOption lets you define that a value might be nullable. I do have a lot of properties in my collections which might be nullable; mostly string | null, Date | null and number | null.

Whenever I attempt to sort by any of these nullable properties, I get typescript errors unless I override the type by casting without the null:

list.sort(
  byValues([
    [(i) => i.releasedAt as string, byDate({ nullable: true, desc })],
  ])
);

If I don't to this explicit cast, I get two type errors from the ByValuesSorter type:

Type '(i: { ..., releasedAt: string | null; }) => string | null' is not assignable to type 'TypeError'.ts(2322)
Type 'sortable<datable>' is not assignable to type '"Sortable type does not match with value provider."'.ts(2322)

Is it possible to modify the types to allow nullable types if the nullable option is set to true?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.