{"id":23413637,"url":"https://github.com/rmdm/nodups","last_synced_at":"2025-04-12T05:43:32.366Z","repository":{"id":79609686,"uuid":"91236783","full_name":"rmdm/nodups","owner":"rmdm","description":" No dups, no doubts","archived":false,"fork":false,"pushed_at":"2020-06-01T01:21:28.000Z","size":2347,"stargazers_count":14,"open_issues_count":9,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-12T05:43:24.119Z","etag":null,"topics":["duplicates","nodups","uniq","unique"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rmdm.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2017-05-14T10:45:41.000Z","updated_at":"2019-05-05T16:44:58.000Z","dependencies_parsed_at":"2023-05-15T11:30:45.661Z","dependency_job_id":null,"html_url":"https://github.com/rmdm/nodups","commit_stats":{"total_commits":30,"total_committers":3,"mean_commits":10.0,"dds":"0.16666666666666663","last_synced_commit":"0cbc9711fea8120d0a3799ef2ddaa4e1fbb5e71b"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmdm%2Fnodups","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmdm%2Fnodups/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmdm%2Fnodups/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmdm%2Fnodups/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rmdm","download_url":"https://codeload.github.com/rmdm/nodups/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248525156,"owners_count":21118616,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["duplicates","nodups","uniq","unique"],"created_at":"2024-12-22T19:53:53.844Z","updated_at":"2025-04-12T05:43:32.342Z","avatar_url":"https://github.com/rmdm.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/rmdm/nodups.svg?branch=master)](https://travis-ci.org/rmdm/nodups)\n[![Coverage Status](https://coveralls.io/repos/github/rmdm/nodups/badge.svg?branch=master)](https://coveralls.io/github/rmdm/nodups?branch=master) [![Greenkeeper badge](https://badges.greenkeeper.io/rmdm/nodups.svg)](https://greenkeeper.io/)\n\nnodups\n=====\n\n**nodups** is a small yet powerful library specialized in working with arrays basically to get unique values and to drop duplicates. But it's more than just that. Let's see this in action:\n\nUsage\n=====\n\nFirst of all, **nodups** basic usage, without any options, allows you to get unique values of the passed array:\n\n```javascript\nnodups([ 1, { a: 5 }, 2, { a: 5 },  1 ])\n// result is [ 1, { a: 5 }, 2 ]\n```\n\nIt leaves the original array unchainged and returns resulting array with unique values in the order of appearence.\n\nNext, to change the original array directly just pass **`inplace`** option:\n\n```javascript\nconst array = [ 1, { a: 5 }, 2, { a: 5 },  1 ]\nnodups(array, { inplace: true })\n// array now contains [ 1, { a: 5 }, 2 ]\n```\n\n**nodups** compares objects values in depth and only checks own enumerable properties of the objects. Primitive properties and values are compared with [`SameValueZero`](https://www.ecma-international.org/ecma-262/8.0/#sec-samevaluezero) algorithm - that means **nodups** treats `NaN` values as equal to each other by default:\n\n```javascript\nnodups([ NaN, 0, NaN, NaN ])\n// result is [ NaN, 0 ]\n```\nTo change the way **nodups** compares values you can pass **`compare`** option with the compare function:\n\n```javascript\nnodups([ 1, 5, 7, 14, 19, 33, 36 ], { compare: (a, b) =\u003e ~~(a/10) === ~~(b/10) })\n// result is [ 1, 14, 33 ]\n```\n\nYou may also pass `'==='` and `'=='` shorthands with **`compare`**:\n\n```javascript\nconst obj = { a: 1 }\nnodups([ obj, { a: 1 }, obj, { a: 1 }, obj ], { compare: '===' })\n// result is [ obj, { a: 1 }, { a: 1 } ]\n\nnodups([ 0, '', false, [] ], { compare: '==' })\n// result is [ 0 ]\n```\n\nIf you would like to change the strictness of comparison primitive properties and values are compared with, you may pass **`strict`** option with `false` value:\n\n```javascript\nnodups([ { a: 1 }, { a: '1' } ], { strict: false })\n// result is [ { a: 1 } ]\n```\n\nPlease note that `{ strict: false }` and `{ compare: '==' }` are different concepts:\n\n```javascript\nnodups([ 0, '', false, NaN, NaN, { a: 1 }, { a: '1' }, { a: '1' } ], { strict: false })\n// result is [ 0, NaN, { a: 1 } ]\n\nnodups([ 0, '', false, NaN, NaN, { a: 1 }, { a: '1' }, { a: '1' } ], { compare: '==' })\n// result is [ 0, NaN, NaN, { a: 1 }, { a: '1' }, { a: '1' } ]\n```\n\nWhen you know that your array is sorted you can gain additional performance by passing **`sorted`** option:\n\n```javascript\nnodups([ 1, 1, 1, 3, 3, 4, 5 ], { sorted: true })\n// result is [ 1, 3, 4, 5 ]\n```\n\nBut be careful, in case of not sorted array using **`sorted`** would lead to failure to drop all duplicates:\n\n```javascript\nnodups([ 1, 3, 1, 1, 3, 4, 5 ], { sorted: true })\n// result is [ 1, 3, 1, 3, 4, 5 ]\n```\n\nAs already noted, **nodups** by default compares objects in depth by all their own enumerable properties. To restrict set of properties by which objects are compared you can use **`by`**:\n\n```javascript\nnodups([\n    { a: 1, b: 3 },\n    { a: 2, b: 4 },\n    { a: 1, b: 5 },\n], { by: [ 'a' ] })\n// result is [\n//     { a: 1, b: 3 },\n//     { a: 2, b: 4 },\n// ]\n```\n\nAnd to ignore some of the properties you can use **`skip`**:\n\n```javascript\nnodups([\n    { a: 1, b: 3 },\n    { a: 2, b: 4 },\n    { a: 1, b: 5 },\n], { skip: [ 'b' ] })\n// result is [\n//     { a: 1, b: 3 },\n//     { a: 2, b: 4 },\n// ]\n```\n\nIf both are specified, **`by`** wins:\n\n```javascript\nnodups([\n    { a: 1, b: 3 },\n    { a: 2, b: 4 },\n    { a: 1, b: 5 },\n], { by: [ 'a' ], skip: [ 'a' ] })\n// result is [\n//     { a: 1, b: 3 },\n//     { a: 2, b: 4 },\n// ]\n```\n\n**`by`** and **`skip`** options accept path or array of paths in objects. Each path may be represented as either `.`-separated keys of each object level or as array of keys of each level (similar to **lodash** notion of paths):\n\n```javascript\nnodups([\n    { a: { b: 1, c: 2 }, d: 7 },\n    { a: { b: 5, c: 4 }, d: 8 },\n    { a: { b: 1, c: 2 }, d: 9 },\n], { by: [ 'a.b', [ 'a', 'c' ] ] })\n// result is [\n//     { a: { b: 1, c: 2 }, d: 7 },\n//     { a: { b: 5, c: 4 }, d: 8 },\n// ]\n```\n\nThough normally we want to drop duplicates, sometimes it is useful to know what are they or how many, so **nodups** provides you with **`onUnique`** option. **`onUnique`** option value is expected to be a function with the following signature: `(unique, duplicates, index, uniques)` and it is called for each unique value:\n\n```javascript\nnodups([\n    { a: 1 },\n    { a: 2 },\n    { a: 1 },\n], { onUnique: (unique, duplicates) =\u003e unique.dups = duplicates.length })\n// result is [\n//     { a: 1, dups: 1 },\n//     { a: 2, dups: 0 },\n// ]\n```\n\n**`onUnique`** can be also uses to change resulting array of unique values:\n\n```javascript\nnodups([ 1, 3, 2, 3 ], { onUnique: (uniq, dups, i, uniqs) =\u003e uniqs[i] = uniq * 2 })\n// result is [ 2, 6, 4 ]\n```\n\nAnd, of course, options can be intermixed!\n\nInstallation\n============\n\n```sh\nnpm i nodups\n```\n\nPolyfill\n========\n\nIf you would like **nodups** method to be available on array instances like that:\n\n```javascript\n[ 1, 1, 1 ].nodups() // result is [ 1 ]\n```\n\nthan you can `polyfill` it:\n\n```javascript\nrequire('nodups').polyfill()\n// or\nrequire('nodups/polyfill')\n// or\nimport nodups from 'nodups/polyfill'\n```\n\nIn particular, it is handy in case of method chaining:\n\n```javascript\narray\n    .nodups()\n    .map(x =\u003e x.category)\n    .nodups()\n    .filter(x =\u003e x.startsWith('_'))\n    .map(x =\u003e getType(x))\n    .nodups()\n```\n\n_Credits to **@zlumer** for his proposal on the polyfill and example._\n\nOptions\n=======\n\nTo summarize [usage](#usage) section here is more formal description of **nodups** options:\n\n- **`inplace`** (Boolean) - drop duplicates from original array.\n- **`compare`** (Function(a, b)|'==='|'==') - custom comparison function of any two array elements or string shorthand.\n- **`strict`** (Boolean) - `true` by default. Compare objects' primitive properties with sligtly changed `==` operation (the only difference is that `NaN` values are treated as equal).\n- **`sorted`** (Boolean) - tells `nodups` that array is sorted and performance optimization can be applied.\n- **`by`** (String|Array) - compare objects only by own enumerable properties specified by the paths.\n- **`skip`** (String|Array) - compare object only by own enumerable properties execept ones specified by the paths.\n- **`onUnique`** - (Function(unique, duplicated, index, uniques)) - callback fired for each unique element. Allows to do some additional work with duplicates.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frmdm%2Fnodups","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frmdm%2Fnodups","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frmdm%2Fnodups/lists"}