Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(array): impl faster splice one element on array #24

Merged
merged 1 commit into from
May 9, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ script:
after_script:
- 'npm i codecov && codecov'
- 'node benchmark/map.js'
- 'node benchmark/array_splice.js'
148 changes: 148 additions & 0 deletions benchmark/array_splice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/**
* Copyright(c) node-modules and other contributors.
* MIT Licensed
*
* Authors:
* fengmk2 <fengmk2@gmail.com> (http://fengmk2.com)
*/

'use strict';

/**
* Module dependencies.
*/

var crypto = require('crypto');
var utility = require('../');

var Benchmark = require('benchmark');
var benchmarks = require('beautify-benchmark');
var suite = new Benchmark.Suite();

function arraySplice(array, index) {
array.splice(index, 1);
return array;
}

function spliceOne(array, index) {
for (var i = index, k = i + 1, n = array.length; k < n; i += 1, k += 1) {
array[i] = array[k];
}
array.pop();
return array;
}

class SubArray extends Array {
spliceOne(index) {
for (let i = index, k = i + 1, n = this.length; k < n; i += 1, k += 1) {
this[i] = this[k];
}
this.pop();
return this;
}
}

console.log('arraySplice([1, 2, 3], 1): %j', arraySplice([1, 2, 3], 1));
console.log('new SubArray(1, 2, 3).spliceOne(1): %j', new SubArray(1, 2, 3).spliceOne(1));
console.log('spliceOne([1, 2, 3], 1): %j', spliceOne([1, 2, 3], 1));
console.log('arraySplice([1, 2, 3, 4, 5, 6, 7, 8, 9], 6): %j',
arraySplice([1, 2, 3, 4, 5, 6, 7, 8, 9], 6));
console.log('new SubArray(1, 2, 3, 4, 5, 6, 7, 8, 9).spliceOne(6): %j',
new SubArray(1, 2, 3, 4, 5, 6, 7, 8, 9).spliceOne(6));
console.log('spliceOne([1, 2, 3, 4, 5, 6, 7, 8, 9], 6): %j',
spliceOne([1, 2, 3, 4, 5, 6, 7, 8, 9], 6));

suite

.add('arraySplice([1, 2, 3], 1)', function() {
arraySplice([1, 2, 3], 1);
})
.add('new SubArray(1, 2, 3).spliceOne(1)', function() {
new SubArray(1, 2, 3).spliceOne(1);
})
.add('spliceOne([1, 2, 3], 1)', function() {
spliceOne([1, 2, 3], 1);
})

.add('arraySplice([1, 2, 3, 4, 5, 6, 7, 8, 9], 6)', function() {
arraySplice([1, 2, 3, 4, 5, 6, 7, 8, 9], 6);
})
.add('new SubArray(1, 2, 3, 4, 5, 6, 7, 8, 9).spliceOne(6)', function() {
new SubArray(1, 2, 3, 4, 5, 6, 7, 8, 9).spliceOne(6);
})
.add('spliceOne([1, 2, 3, 4, 5, 6, 7, 8, 9], 6)', function() {
spliceOne([1, 2, 3, 4, 5, 6, 7, 8, 9], 6);
})

.add('arraySplice(new Array(20), 11)', function() {
arraySplice(new Array(20), 11);
})
.add('new SubArray(new Array(20)).spliceOne(11)', function() {
new SubArray(new Array(20)).spliceOne(11);
})
.add('spliceOne(new Array(20), 11)', function() {
spliceOne(new Array(20), 11);
})

.add('arraySplice(new Array(50), 30)', function() {
arraySplice(new Array(50), 30);
})
.add('new SubArray(new Array(50)).spliceOne(30)', function() {
new SubArray(new Array(50)).spliceOne(30);
})
.add('spliceOne(new Array(50), 30)', function() {
spliceOne(new Array(50), 30);
})

.add('arraySplice(new Array(100), 80)', function() {
arraySplice(new Array(100), 80);
})
.add('new SubArray(new Array(100)).spliceOne(80)', function() {
new SubArray(new Array(100)).spliceOne(80);
})
.add('spliceOne(new Array(100), 80)', function() {
spliceOne(new Array(100), 80);
})


.on('cycle', function(event) {
benchmarks.add(event.target);
})
.on('start', function(event) {
console.log('\n map Benchmark\n node version: %s, date: %s\n Starting...',
process.version, Date());
})
.on('complete', function done() {
benchmarks.log();
})
.run({ 'async': false });

// node benchmark/array_splice.js
//
// arraySplice([1, 2, 3], 1): [1,3]
// new SubArray(1, 2, 3).spliceOne(1): [1,3]
// spliceOne([1, 2, 3], 1): [1,3]
// arraySplice([1, 2, 3, 4, 5, 6, 7, 8, 9], 6): [1,2,3,4,5,6,8,9]
// new SubArray(1, 2, 3, 4, 5, 6, 7, 8, 9).spliceOne(6): [1,2,3,4,5,6,8,9]
// spliceOne([1, 2, 3, 4, 5, 6, 7, 8, 9], 6): [1,2,3,4,5,6,8,9]
//
// map Benchmark
// node version: v6.1.0, date: Sun May 08 2016 23:02:25 GMT+0800 (CST)
// Starting...
// 15 tests completed.
//
// arraySplice([1, 2, 3], 1) x 3,391,759 ops/sec ±1.75% (77 runs sampled)
// new SubArray(1, 2, 3).spliceOne(1) x 2,146,665 ops/sec ±2.44% (78 runs sampled)
// spliceOne([1, 2, 3], 1) x 30,957,606 ops/sec ±2.30% (76 runs sampled)
// arraySplice([1, 2, 3, 4, 5, 6, 7, 8, 9], 6) x 3,393,631 ops/sec ±1.58% (81 runs sampled)
// new SubArray(1, 2, 3, 4, 5, 6, 7, 8, 9).spliceOne(6) x 1,898,975 ops/sec ±1.36% (81 runs sampled)
// spliceOne([1, 2, 3, 4, 5, 6, 7, 8, 9], 6) x 23,286,263 ops/sec ±2.40% (72 runs sampled)
// arraySplice(new Array(20), 11) x 3,424,955 ops/sec ±1.39% (79 runs sampled)
// new SubArray(new Array(20)).spliceOne(11) x 1,703,608 ops/sec ±1.43% (79 runs sampled)
// spliceOne(new Array(20), 11) x 6,371,527 ops/sec ±8.68% (71 runs sampled)
// arraySplice(new Array(50), 30) x 2,961,652 ops/sec ±3.94% (81 runs sampled)
// new SubArray(new Array(50)).spliceOne(30) x 1,738,558 ops/sec ±2.28% (84 runs sampled)
// spliceOne(new Array(50), 30) x 2,887,661 ops/sec ±4.01% (74 runs sampled)
// arraySplice(new Array(100), 80) x 2,803,597 ops/sec ±2.12% (86 runs sampled)
// new SubArray(new Array(100)).spliceOne(80) x 1,695,942 ops/sec ±0.91% (88 runs sampled)
// spliceOne(new Array(100), 80) x 3,175,629 ops/sec ±1.28% (86 runs sampled)
36 changes: 32 additions & 4 deletions lib/array.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/*!
* utility - lib/array.js
*
* Copyright(c) 2012 - 2014 fengmk2 <fengmk2@gmail.com>
/**
* Copyright(c) node-modules and other contributors.
* MIT Licensed
*
* Authors:
* fengmk2 <fengmk2@gmail.com> (http://fengmk2.com)
*/

"use strict";
Expand All @@ -27,3 +28,30 @@ exports.randomSlice = function randomSlice(arr, num) {
}
return a;
};

/**
* Remove one exists element from an array
* @param {Array} arr
* @param {Number} index - remove element index
* @return {Array} the array instance
*/
exports.spliceOne = function spliceOne(arr, index) {
if (index < 0) {
index = arr.length + index;
// still negative, not found element
if (index < 0) {
return arr;
}
}

// don't touch
if (index >= arr.length) {
return arr;
}

for (var i = index, k = i + 1, n = arr.length; k < n; i += 1, k += 1) {
arr[i] = arr[k];
}
arr.pop();
return arr;
};
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"lib"
],
"scripts": {
"test": "ava test/**/*.test.js",
"test": "npm run lint && ava test/**/*.test.js",
"test-cov": "nyc ava test/**/*.test.js && nyc report --reporter=lcov",
"lint": "jshint .",
"ci": "npm run lint && npm run test-cov",
Expand Down
21 changes: 21 additions & 0 deletions test/array.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,24 @@ test('randomSlice() should return sub items', t => {
t.deepEqual(utils.randomSlice(arr, 0), arr);
t.is(utils.randomSlice(arr, 6).length, 6);
});

test('spliceOne() should work', t => {
t.deepEqual(utils.spliceOne([1, 2, 3], 0), [2, 3]);
t.deepEqual(utils.spliceOne([1, 2, 3], 1), [1, 3]);
t.deepEqual(utils.spliceOne([1, 2, 3], 2), [1, 2]);
t.deepEqual(utils.spliceOne([1, 2, 3], 3), [1, 2, 3]);
t.deepEqual(utils.spliceOne([1, 2, 3], 4), [1, 2, 3]);
t.deepEqual(utils.spliceOne([1, 2, 3], 5), [1, 2, 3]);
t.deepEqual(utils.spliceOne([1, 2, 3], -0), [2, 3]);
t.deepEqual(utils.spliceOne([1, 2, 3], -1), [1, 2]);
t.deepEqual(utils.spliceOne([1, 2, 3], -2), [1, 3]);
t.deepEqual(utils.spliceOne([1, 2, 3], -3), [2, 3]);
t.deepEqual(utils.spliceOne([1, 2, 3], -4), [1, 2, 3]);
t.deepEqual(utils.spliceOne([1, 2, 3], -5), [1, 2, 3]);
t.deepEqual(utils.spliceOne([1, 2, 3], 100), [1, 2, 3]);

t.deepEqual(utils.spliceOne([1], 0), []);
t.deepEqual(utils.spliceOne([1], 1), [1]);
t.deepEqual(utils.spliceOne([], 0), []);
t.deepEqual(utils.spliceOne([], 100), []);
});