Skip to content

Commit

Permalink
compare values with the same-value equality algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
shinnn committed Aug 23, 2018
1 parent eb8969b commit 6ef1aa7
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 136 deletions.
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![Build Status](https://travis-ci.org/shinnn/array-has-duplicates.svg?branch=master)](https://travis-ci.org/shinnn/array-has-duplicates)
[![Coverage Status](https://img.shields.io/coveralls/shinnn/array-has-duplicates.svg)](https://coveralls.io/github/shinnn/array-has-duplicates)

Check if an [array](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4) includes duplicated values or not
Check if an `Array` includes duplicated values or not

```javascript
arrayHasDuplicates([1, 2, 3, 4, 5]); //=> false
Expand All @@ -23,28 +23,31 @@ npm install array-has-duplicates

### arrayHasDuplicates(*array*)

*array*: `Array`
Return: `Boolean`
*array*: `Array<any>`
Return: `boolean`

It returns `true` if the array includes at least one pair of duplicated values, otherwise returns `false`.

*"Duplicated"* means a value is [strictly equal (`===`)][strictequal] to the other value.

```javascript
arrayHasDuplicates([3, 3, 3]); //=> true
arrayHasDuplicates([3, '3', [3]]); //=> false
```

Also it ignores all the empty indexes.
*"Duplicated"* means a value is identical to with another value in the ECMAScript [same-value equality](https://developer.mozilla.org/docs/Web/JavaScript/Equality_comparisons_and_sameness#Same-value_equality) level.

```javascript
arrayHasDuplicates([0, -0]); //=> false
```

Note that it ignores all empty indexes.

```javascript
arrayHasDuplicates([, , , undefined]); //=> false
arrayHasDuplicates([, undefined]);
//=> false, though array[0] and array[1] are both `undefined`
```

## License

Copyright (c) 2016 - 2018 [Shinnosuke Watanabe](https://github.com/shinnn)

Licensed under [the MIT License](./LICENSE).

[strictequal]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Identity_strict_equality_()
21 changes: 0 additions & 21 deletions benchmark/index-of.js

This file was deleted.

3 changes: 0 additions & 3 deletions benchmark/main.js

This file was deleted.

56 changes: 0 additions & 56 deletions benchmark/run.js

This file was deleted.

12 changes: 0 additions & 12 deletions benchmark/set.js

This file was deleted.

38 changes: 21 additions & 17 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,36 @@ var appendType = require('append-type');
* https://github.com/shinnn/array-has-duplicates
*/

function removeEmptyArrayElement() {
return true;
var objectIs = Object.is || function objectIs(x, y) {
if (x === y) {
return x !== 0 || 1 / x === 1 / y;
}

return x !== x && y !== y; // eslint-disable-line no-self-compare
};

function is(x) {
return objectIs(this, x);
}

var hasSet = typeof Set === 'function';
function isAlradyFound(val) {
if (this.some(is, val)) {
return true;
}

this.push(val);

return false;
}

function arrayHasDuplicates(arr) {
if (!Array.isArray(arr)) {
throw new TypeError('Expected an Array to check if it includes duplicated values, but got ' + appendType(arr) + '.');
}

arr = arr.filter(removeEmptyArrayElement);

if (arr.length < 300 || !hasSet) {
var len = arr.length;

while (len--) {
if (arr.indexOf(arr[len]) !== len) {
return true;
}
}

return false;
}
var foundValues = [];

return arr.length !== 0 && arr.length !== new Set(arr).size;
return arr.some(isAlradyFound, foundValues);
}

module.exports = arrayHasDuplicates;
38 changes: 21 additions & 17 deletions index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,34 @@
*/
import appendType from 'append-type';

function removeEmptyArrayElement() {
return true;
var objectIs = Object.is || function objectIs(x, y) {
if (x === y) {
return x !== 0 || 1 / x === 1 / y;
}

return x !== x && y !== y; // eslint-disable-line no-self-compare
};

function is(x) {
return objectIs(this, x);
}

var hasSet = typeof Set === 'function';
function isAlradyFound(val) {
if (this.some(is, val)) {
return true;
}

this.push(val);

return false;
}

export default function arrayHasDuplicates(arr) {
if (!Array.isArray(arr)) {
throw new TypeError('Expected an Array to check if it includes duplicated values, but got ' + appendType(arr) + '.');
}

arr = arr.filter(removeEmptyArrayElement);

if (arr.length < 300 || !hasSet) {
var len = arr.length;

while (len--) {
if (arr.indexOf(arr[len]) !== len) {
return true;
}
}

return false;
}
var foundValues = [];

return arr.length !== 0 && arr.length !== new Set(arr).size;
return arr.some(isAlradyFound, foundValues);
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"author": "Shinnosuke Watanabe (https://github.com/shinnn)",
"license": "MIT",
"scripts": {
"bench": "node -p \"require('chalk').yellow('NOTE: Smaller is better.\\n')\" && node benchmark/index-of.js && node benchmark/set.js && node benchmark/main.js",
"prebuild": "eslint .",
"build": "rollup --config=node:module",
"pretest": "npm run-script build",
Expand All @@ -23,6 +22,8 @@
"duplicate",
"duplicates",
"duplicated",
"same",
"same-value-equality",
"check",
"if"
],
Expand Down
6 changes: 6 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ test('arrayHasDuplicates()', t => {
'should compare values with the strict equal operator.'
);

t.equal(
arrayHasDuplicates([0, -0]),
false,
'should differentiate negative zero from positive zero.'
);

t.equal(
arrayHasDuplicates([, , , undefined]), // eslint-disable-line no-sparse-arrays
false,
Expand Down

0 comments on commit 6ef1aa7

Please sign in to comment.