Skip to content

Commit

Permalink
Initial import
Browse files Browse the repository at this point in the history
  • Loading branch information
alexindigo committed Dec 2, 2015
1 parent 8098183 commit 4de6dd4
Show file tree
Hide file tree
Showing 9 changed files with 314 additions and 27 deletions.
14 changes: 14 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org

root = true

[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true

[**.{css,hbs,js,json,md,scss}]
indent_style = space
indent_size = 2
insert_final_newline = true
32 changes: 32 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"rules": {
"indent": [2, 2, {"SwitchCase": 1}],
"quotes": [2, "single"],
"linebreak-style": [2, "unix"],
"semi": [2, "always"],
"curly": [2, "multi-line"],
"handle-callback-err": [2, "^err"],
"valid-jsdoc": [2, {
"requireReturn": false,
"requireReturnDescription": false,
"prefer": {
"return": "returns"
}
}],
"key-spacing": 0,
"strict": 0,
"no-underscore-dangle": 0,
"no-use-before-define": 0,
"dot-notation": 0,
"eol-last": 0,
"no-new": 0,
"semi-spacing": 0,
"no-multi-spaces": 0,
"eqeqeq": 0,
"no-mixed-requires": 0
},
"env": {
"node": true,
"browser": true
}
}
28 changes: 2 additions & 26 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,27 +1,3 @@
# Logs
logs
coverage/
node_modules/
*.log

# Runtime data
pids
*.pid
*.seed

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
10 changes: 10 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.editorconfig
.eslint
.travis.yml

*.log

coverage/
node_modules/

test.js
9 changes: 9 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
sudo: false
language: node_js
node_js:
- "0.12"
- "iojs"
- "4.2"
- "stable"
after_script:
- "cat coverage/lcov.info | ./node_modules/.bin/coveralls"
64 changes: 63 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,64 @@
# cartesian
# Cartesian
Computes the cartesian product of arrays provided by an array or an object

[![Build Status](https://img.shields.io/travis/alexindigo/cartesian/master.svg?style=flat-square)](https://travis-ci.org/alexindigo/cartesian)
[![Coverage Status](https://img.shields.io/coveralls/alexindigo/cartesian/master.svg?style=flat-square)](https://coveralls.io/github/alexindigo/cartesian?branch=master)

## Install

```
npm install cartesian --save
```

## Examples

```javascript
var cartesian = require('cartesian');
```

### Array or arrays:

```javascript
cartesian([
['A', 'B', 'C'],
['M'],
['X', 'Y'],
'Z'
]);

// =>
// [
// [ 'A', 'M', 'X', 'Z' ],
// [ 'A', 'M', 'Y', 'Z' ],
// [ 'B', 'M', 'X', 'Z' ],
// [ 'B', 'M', 'Y', 'Z' ],
// [ 'C', 'M', 'X', 'Z' ],
// [ 'C', 'M', 'Y', 'Z' ]
// ]
```

### Object with array properties:

```javascript
cartesian({
cdn : ['image1', 'image2'],
path : '/dir',
files: ['file1', 'file2', 'file3']
});

// =>
// [
// { cdn: 'image1', path: '/dir', files: 'file1' },
// { cdn: 'image1', path: '/dir', files: 'file2' },
// { cdn: 'image1', path: '/dir', files: 'file3' },
// { cdn: 'image2', path: '/dir', files: 'file1' },
// { cdn: 'image2', path: '/dir', files: 'file2' },
// { cdn: 'image2', path: '/dir', files: 'file3' }
// ]
```

For more examples check out [`test.js`](test.js).

## License

[MIT](LICENSE)
80 changes: 80 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
var extend = require('xtend/immutable');

// Public API
module.exports = cartesian;

/**
* Creates cartesian product of the provided properties
*
* @param {object|array} list - list of (array) properties or array of arrays
* @returns {array} all the combinations of the properties
*/
function cartesian(list)
{
var last, init, keys, product = [];

if (Array.isArray(list))
{
init = [];
last = list.length - 1;
}
else
{
init = {};
keys = Object.keys(list);
last = keys.length - 1;
}

function add(row, i)
{
var j, k, r;

k = keys ? keys[i] : i;

// either array or not, not expecting objects here
Array.isArray(list[k]) || (list[k] = [list[k]]);

for (j=0; j < list[k].length; j++)
{
r = clone(row);
store(r, list[k][j], k);

if (i == last)
{
product.push(r);
}
else
{
add(r, i + 1);
}
}
}

add(init, 0);

return product;
}

/**
* Clones (shallow copy) provided object or array
*
* @param {object|array} obj - object or array to clone
* @returns {object|array} - shallow copy of the provided object or array
*/
function clone(obj)
{
return Array.isArray(obj) ? [].concat(obj) : extend(obj);

This comment has been minimized.

Copy link
@jimmywarting

jimmywarting May 22, 2021

Don't need xtend They deprecated it

return Array.isArray(obj) ? [...obj] : {...obj}

}

/**
* Stores provided element in the provided object or array
*
* @param {object|array} obj - object or array to add to
* @param {mixed} elem - element to add
* @param {string|number} key - object's property key to add to
* @returns {void}
*/
function store(obj, elem, key)
{
Array.isArray(obj) ? obj.push(elem) : (obj[key] = elem);
}
45 changes: 45 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"name": "cartesian",
"version": "1.0.0",
"description": "Computes the cartesian product of arrays provided by an array or an object",
"main": "index.js",
"scripts": {
"test": "istanbul cover test.js",
"lint": "eslint *.js",
"debug": "node test.js",
"check": "istanbul check-coverage coverage/coverage.json"
},
"pre-commit": [
"lint",
"test",
"check"
],
"repository": {
"type": "git",
"url": "git+https://github.com/alexindigo/cartesian.git"
},
"keywords": [
"cartesian",
"cartesian product",
"array",
"object",
"properties",
"permutation",
"combination"
],
"author": "Alex Indigo <[email protected]>",
"license": "MIT",
"bugs": {
"url": "https://github.com/alexindigo/cartesian/issues"
},
"homepage": "https://github.com/alexindigo/cartesian#readme",
"devDependencies": {
"coveralls": "^2.11.4",
"eslint": "^1.10.3",
"istanbul": "^0.4.1",
"pre-commit": "^1.1.2"
},
"dependencies": {
"xtend": "^4.0.1"
}
}
59 changes: 59 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
var assert = require('assert');
var cartesian = require('./');

var subjects = [

// simple
{
input: ['A', 'B', 'C'],
expected: [['A', 'B', 'C']]
},

// array of arrays
{
input: [
['A', 'B', 'C'],
['M'],
['X', 'Y'],
'Z'
],
expected: [
[ 'A', 'M', 'X', 'Z' ],
[ 'A', 'M', 'Y', 'Z' ],
[ 'B', 'M', 'X', 'Z' ],
[ 'B', 'M', 'Y', 'Z' ],
[ 'C', 'M', 'X', 'Z' ],
[ 'C', 'M', 'Y', 'Z' ]
]
},

// simple object
{
input: {a: 'A', b: 'B', c: 'C'},
expected: [{a: 'A', b: 'B', c: 'C'}]
},

// object with arrays
{
input: {
cdn: ['image1', 'image2'],
path: '/dir',
files: ['file1', 'file2', 'file3']
},
expected: [
{ cdn: 'image1', path: '/dir', files: 'file1' },
{ cdn: 'image1', path: '/dir', files: 'file2' },
{ cdn: 'image1', path: '/dir', files: 'file3' },
{ cdn: 'image2', path: '/dir', files: 'file1' },
{ cdn: 'image2', path: '/dir', files: 'file2' },
{ cdn: 'image2', path: '/dir', files: 'file3' }
]
}
];


subjects.forEach(function(test)
{
var product = cartesian(test.input);
assert.deepEqual(product, test.expected);
});

0 comments on commit 4de6dd4

Please sign in to comment.