Javascript - Permutations remove the duplicates elements - javascript

that is found here in stack but i want somes changes.
function perms(data) {
if (!(data instanceof Array)) {
throw new TypeError("input data must be an Array");
}
data = data.slice(); // make a copy
var permutations = [],
stack = [];
function doPerm() {
if (data.length == 0) {
permutations.push(stack.slice());
}
for (var i = 0; i < data.length; i++) {
var x = data.splice(i,1);
stack.push(x);
doPerm();
stack.pop();
data.splice(i, 0, x);
}
}
doPerm();
return permutations;
}
var input = "552".split('');
var result = perms(input);
for (var i = 0; i < result.length; i++) {
result[i] = result[i].join('-');
}
The result of that is :
5-5-2
5-2-5
5-5-2
5-2-5
2-5-5
2-5-5
but , are 3 elements duplicates the result must be :
5-5-2
5-2-5
2-5-5
how can i fix that issue .

Basically, you have one issue,
var x = data.splice(i, 1)[0];
// ^^^ is missing
because you get an array with splicing. The result is a deep nested array with
data.splice(i, 0, x);
This inserts the array later on position i.
For preventing duplicates, you need a check, if the actual value is already inserted in the result set with
permutations.some(function (a) {
return a.every(function (b, j) {
return stack[j] === b;
});
}) || permutations.push(stack.slice());
which test the arrays and if no match, the push is performed.
function perms(data) {
if (!(data instanceof Array)) {
throw new TypeError("input data must be an Array");
}
data = data.slice(); // make a copy
var permutations = [],
stack = [],
hash = Object.create(null);
function doPerm() {
if (data.length == 0) {
permutations.some(function (a) {
return a.every(function (b, j) {
return stack[j] === b;
});
}) || permutations.push(stack.slice());
return;
}
for (var i = 0; i < data.length; i++) {
var x = data.splice(i, 1)[0];
stack.push(x);
doPerm();
stack.pop();
data.splice(i, 0, x);
}
}
doPerm();
return permutations;
}
var input = "552".split('');
var result = perms(input);
for (var i = 0; i < result.length; i++) {
result[i] = result[i].join('-');
}
console.log(result);

Check if array array is present within resulting array before calling .push() using Array.prototype.some(), Array.prototype.join()
function p(a, b, res) {
var b = b || [],
res = res || [],
len = a.length;
if (!len) {
// check if `res` contains `b.join("")`
if (!res.length
|| !res.some(function(n) {
return n.join("") === b.join("")
}))
res.push(b)
} else {
for (var i = 0
; i < len; p(a.slice(0, i).concat(a.slice(i + 1, len))
, b.concat(a[i]), res)
, i++);
}
return res
}
var result = p("552".split(""));
result = result.map(function(res) {
return res.join("-")
});
console.log(result);

Related

How to get all possible combinations of elements in an array including order and lengths

function getAllCombinations(arr) {
var f = function(arr) {
var result = [];
var temp = [];
for (var i = 0; i < arr.length; i++) {
temp = [];
temp.push(arr[i]);
result.push(temp);
for (var j = 0; j < arr.length; j++) {
if (j != i) {
temp = [];
temp.push(arr[i]);
temp.push(arr[j]);
result.push(temp);
for (var k = 0; k < arr.length; k++) {
if (k != i && k != j) {
temp = [];
temp.push(arr[i]);
temp.push(arr[j]);
temp.push(arr[k]);
result.push(temp);
for (var l = 0; l < arr.length; l++) {
if (l != i && l != j && l != k) {
temp = [];
temp.push(arr[i]);
temp.push(arr[j]);
temp.push(arr[k]);
temp.push(arr[l]);
result.push(temp);
}
}
}
}
}
}
}
return result;
}
return f(arr);
}
//call this function
console.log(getAllCombinations(["a", "b", "c", "d"]));
[["a"],["a","b"],["a","b","c"],["a","b","c","d"],["a","b","d"],["a","b","d","c"],["a","c"],["a","c","b"],["a","c","b","d"],["a","c","d"],["a","c","d","b"],["a","d"],["a","d","b"],["a","d","b","c"],["a","d","c"],["a","d","c","b"],["b"],["b","a"],["b","a","c"],["b","a","c","d"],["b","a","d"],["b","a","d","c"],["b","c"],["b","c","a"],["b","c","a","d"],["b","c","d"],["b","c","d","a"],["b","d"],["b","d","a"],["b","d","a","c"],["b","d","c"],["b","d","c","a"],["c"],["c","a"],["c","a","b"],["c","a","b","d"],["c","a","d"],["c","a","d","b"],["c","b"],["c","b","a"],["c","b","a","d"],["c","b","d"],["c","b","d","a"],["c","d"],["c","d","a"],["c","d","a","b"],["c","d","b"],["c","d","b","a"],["d"],["d","a"],["d","a","b"],["d","a","b","c"],["d","a","c"],["d","a","c","b"],["d","b"],["d","b","a"],["d","b","a","c"],["d","b","c"],["d","b","c","a"],["d","c"],["d","c","a"],["d","c","a","b"],["d","c","b"],["d","c","b","a"]]
A total of 64 combinations for a 4 length array.
The function works fine but I need to make this function recursive. The for loops have to be nested based on the length of the array and the push also increased per nested loop.
Really appreciate some advice.
Finally made it recursive !!
Tried to work down on the the original code posted above moving each loop functionality into simple functions.
function getAllCombinations(inputArray) {
var resultArray = [];
var combine = function() {
for (var i in inputArray) {
var temp = [];
var tempResult = [];
for (var j in arguments) {
tempResult.push(inputArray[arguments[j]]);
if (arguments[j] == i) {
temp = false;
} else if (temp) {
temp.push(arguments[j]);
}
}
if (temp) {
temp.push(i);
combine.apply(null, temp);
}
}
if (tempResult.length > 0) {
resultArray.push(tempResult);
}
return resultArray;
};
return combine();
}
See the older version here.
Result produces 64 unique combinations for a 4 dimensional array
console.log(getAllCombinations(["a", "b", "c", "d"]));
[["a","b","c","d"],["a","b","c"],["a","b","d","c"],["a","b","d"],["a","b"],["a","c","b","d"],["a","c","b"],["a","c","d","b"],["a","c","d"],["a","c"],["a","d","b","c"],["a","d","b"],["a","d","c","b"],["a","d","c"],["a","d"],["a"],["b","a","c","d"],["b","a","c"],["b","a","d","c"],["b","a","d"],["b","a"],["b","c","a","d"],["b","c","a"],["b","c","d","a"],["b","c","d"],["b","c"],["b","d","a","c"],["b","d","a"],["b","d","c","a"],["b","d","c"],["b","d"],["b"],["c","a","b","d"],["c","a","b"],["c","a","d","b"],["c","a","d"],["c","a"],["c","b","a","d"],["c","b","a"],["c","b","d","a"],["c","b","d"],["c","b"],["c","d","a","b"],["c","d","a"],["c","d","b","a"],["c","d","b"],["c","d"],["c"],["d","a","b","c"],["d","a","b"],["d","a","c","b"],["d","a","c"],["d","a"],["d","b","a","c"],["d","b","a"],["d","b","c","a"],["d","b","c"],["d","b"],["d","c","a","b"],["d","c","a"],["d","c","b","a"],["d","c","b"],["d","c"],["d"]]
Here is my solution using a subroutine, and closures. Also slice is very useful here.
If you found this helpful, or if you think other people will find this helpful, don't be afraid to upvote.
function getMyCombinations(coll) {
const result = [];
(function search(currentPerm, letters) {
if (letters.length === 0) return result.push(currentPerm);
let trimArray = letters.slice(1);
letters.forEach(letter => search(currentPerm + letter, trimArray));
})('', coll)
return result;
}
console.log(getMyCombinations(["a", "b", "c", "d"]));
I have refactored my original answer to better align with the users request.
function findPerm(array, currentPerm = '', result =[]) {
if (array.length === 0) return result;
let trimArray = array.slice(1);
array.forEach(v => {
let copy = [...result];
let perm = (currentPerm + v).split('');
let res = copy.push(perm);
result = findPerm(trimArray, currentPerm + v, copy);
});
return result;
};
console.log(findPerm(['a', 'b', 'c', 'd']));
An alternative solution, seems getting the desired output :)
console.log(JSON.stringify(getMyCombinations(["a", "b", "c", "d"])))
function getMyCombinations(arry) {
var len = arry.length;
var tempArray = [];
var result = []
var tempCount = 1;
var createCombinations = function(count){
var singleLevelArray = [];
arry.forEach(function(item){
if(count){//1
if(count > 1){
for(var j = 0; j < tempArray.length; j++){
if(tempArray[j].indexOf(item) === -1){
var x = tempArray[j].slice();
x.push(item);
singleLevelArray.push(x);
result.push(x);
}
}
} else {
for(var k = 0; k < len; k++){
if(item.indexOf(arry[k]) === -1){
tempArray.push([item, arry[k]]);
result.push([item, arry[k]]);
}
}
}
} else {
result.push([item]);
}
})
if(singleLevelArray.length){
tempArray = []
tempArray = singleLevelArray;
}
if(tempCount < len){
createCombinations(tempCount++);
}
return result;
}
return createCombinations()
}

Why is this happening with javascript objects

I am working on a function to map a string that has been split into an array
function arrayDups(a) // a: array to search: as in string split into array.
{
var unique = {}
var dups = [];
var seen = false;
var bypass = {};
for(var i = 0; i < a.length; i++)
{
if(bypass[a[i]] == 'undefined')
{
unique[a[i]] = i+',';
bypass[a[i]] = false;
}
for(var k = i; k < a.length; k++)
{
// so the same char later will not produce duplicate records.
if(unique[a[k]] != 'undefined' && bypass[a[k]] != 'undefined' && !bypass[a[k]])
{
unique[a[k]] += k+',';
if(k == a.length - 1)
{
bypass[a[i]] = true
}
}
}
}
for(var x in unique)
{
dups[dups.length] = x+':'+unique[x]
}
return dups;
}
this is colled in the following context
var testCase = ('disproportionate').split('');
window.onload = function()
{
var test = document.getElementById('res')
test.childNodes[0].data = arrayDups(testCase).join("\n")
}
which produces the following output
d:undefined0,
i:undefined1,10,1,10,
s:undefined2,2,2,
p:undefined3,6,3,6,3,6,3,6,
r:undefined4,8,4,8,4,8,4,8,4,8,
o:undefined5,7,11,5,7,11,5,7,11,5,7,11,5,7,11,5,7,11,
t:undefined9,14,9,14,9,14,9,14,9,14,9,14,9,14,9,14,9,14,9,14,
n:undefined12,12,12,12,12,12,12,12,12,12,12,12,12,
a:undefined13,13,13,13,13,13,13,13,13,13,13,13,13,13,
e:undefined15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
The questions:
where is undefined coming from
and why are the index positions being duplicated when for each iteration of i
k begins at the current i value and should be looking ahead to find index values of duplicate chars
I wouldn't want to answer my own question so I am adding to the original post via edits
Here is what I came up with
function arrayDups(a) // a: array to search: as in string split into array.
{
var unique = {}
var dups = [];
var seen = false;
var bypass = {};
for(var i = 0; i < a.length; i++)
{
if(!bypass.propertyIsEnumerable(a[i]))
{
unique[a[i]] = i+',';
bypass[a[i]] = 'false';
continue;
}
if(bypass.propertyIsEnumerable(a[i]) && bypass[a[i]] == 'false')
{
for(var k = i; k < a.length; k++)
{
// for every instance of a[i] == a[k] unique[a[k]] will be defined
if(a[i] == a[k] && unique.propertyIsEnumerable(a[k]))
{
unique[a[k]] += k+',';
}
if(k == a.length - 1)
{
bypass[a[i]] = 'true'
continue;
}
}
}
}
for(var x in unique)
{
dups[dups.length] = x+':'+unique[x]
}
return dups;
}
And this is the output
d:0,
i:1,10,
s:2,
p:3,6,
r:4,8,
o:5,7,11,
t:9,14,
n:12,
a:13,
e:15,
so now all I have to do is strip the railing ','

Removing empty strings from array

I understand there are other pages on this but I am trying to get my own working and I do not know why it is not working. I am new to node.js.
for (var index in output)
{
if (opt.options.showEmpty != true)
{
var check = arrayIsEmpty(output[index]);
if ( check == true )
{
continue;
}
else
{
var array = removingEmptyString(output[index]);
console.log(index + "\t" + array);
//console.log(index+ "\t" + output[index]);
}
}
}
function removingEmptyString(array)
{
var newArray;
for( var i = 0; i < array.length; i++)
{
if(array[i] != "" || array[i] != null)
{
newArray[i] = array[i];
}
}
return newArray;
}
My result is tree,,, that i was previously getting before the code i wrote. now i get an error of
newArray[i] = array[i];
^
TypeError: Cannot set property '0' of undefined
at removingEmptyString (librarySeeker.js:130:18)
at result (librarySeeker.js:76:19)
at /async/lib/async.js:226:13
at async/lib/async.js:113:25
at async/lib/async.js:24:16
at async/lib/async.js:223:17
at /async/lib/async.js:510:34
at IncomingMessage.<anonymous> (pull.js:295:10)
at IncomingMessage.EventEmitter.emit (events.js:117:20)
at _stream_readable.js:910:16
You could just use the .filter method in Array's prototype.
var pirate = ['a','1','',0];
function arr (value) {
return value.filter(function (item) {
return item !== '';
});
}
arr(pirate);
// <- ['a','1',0]
As an alternative, you might want to consider naming the callback to .filter
var pirate = ['a','1','',0];
function worthy (value) {
return value !== '';
}
pirate.filter(worthy);
// <- ['a','1',0]
In the spirit of learning, here is a working version of your solution:
function removingEmptyString(array) {
'use strict';
var newArray = []; // don't forget to initialize it
for( var i = 0, len = array.length; i < len; i += 1) {
if(typeof array[i] === 'string' && array[i].length > 0) {
// add the string to the end of the new array
newArray.push(array[i]);
}
}
return newArray;
}
The error is saying that newArray has not been initialised, so it cannot assign the 0 property to an undefined object.
You can improve your function to make it work:
function removingEmptyString(array){
var newArray = [];
for( var i = 0; i < array.length; i++){
// empty string and null are falsy values by default is js
if(array[i])
{
// use this if you want to keep "undefined" values in the newArray in place
// of the null ones in the original array
newArray[i] = array[i];
// otherwise just push the values in the new array
// newArray.push(array[i]);
}
}
return newArray;
}

how to get all the combination from a group of arrays

I have for example these arrays:
a1 = ["1", "2", "3"];
a2 = ["a", "b"];
a3 = ["q", "w", "e"];
result = ["1aq", "1aw", "1ae", "1bq", "1bw", ... "3be"];
How could obtain this without nested loops (also using jquery, for example)?
Thanks
I don't see what's wrong with nested loops, but here is a generic solution:
var a = [a1, a2, a3];
var result = [""]; // start with the empty string,
for (var i=0; i<a.length; i++) { // and repeatedly
var ai = a[i],
l = ai.length;
result = $.map(result, function(r) { // make result a new array of
var ns = []; // new combinations of
for (var j=0; j<l; j++) // each of the letters in ai
ns[j] = r + ai[j]; // and the old results
return ns;
}); // using the odds of jQuery.map with returned arrays
}
return result;
No nested loops. Can handle as many arrays as needed.
var result = combine(a1, a2, a3);
function combine() {
return processArrays([].slice.call(arguments), "", []);
function processArrays(arrays, str, res) {
for (var i = 0; i < arrays[0].length; i++) {
if (arrays.length > 1) {
processArrays(arrays.slice(1), str + arrays[0][i], res);
} else {
res.push(str + arrays[0][i]);
}
}
return res;
}
}
Or a slightly different take on the function:
function combine() {
return processArrays([].slice.call(arguments), "", []);
function processArrays(arrays, str, res) {
if (arrays.length === 0)
res.push(str)
else
for (var i = 0; i < arrays[0].length; i++)
processArrays(arrays.slice(1), str + arrays[0][i], res);
return res;
}
}
And here's a no loops version:
var result = combine(a1, a2, a3);
function combine() {
return processArrays(arguments[0], [].slice.call(arguments, 1), "", []);
function processArrays(head, tail, str, res) {
if (head === undefined)
res.push(str)
else
processArray(head[0], head.slice(1), tail, str, res);
return res;
}
function processArray(head, tail, arrays, str, res) {
if (head) {
processArrays(arrays[0], arrays.slice(1), str + head, res);
processArray(tail[0], tail.slice(1), arrays, str, res)
}
}
}
A generic recursive solution:
function combine() {
var target = arguments[0];
if (arguments.length === 1) {
return target; // end of chain, just return the array
}
var result = [];
// compute all combinations without the first array
var combinations = combine.apply(null, Array.prototype.slice.call(arguments, 1));
// put things together
for (var i = 0, l = target.length; i < l; i++) {
var element = target[i];
for (var j = 0, lj = combinations.length; j < lj; j++) {
result.push(element + combinations[j]);
}
}
return result;
}
// Usage
var result = combine(a1, a2, a3);
Another generic solution.
var reduce = function(a, b) {
var r = [];
$.each(a, function(i, ai) {
$.each(b, function(j, bj) {
r.push(ai + bj);
});
});
return r;
};
var result = reduce(reduce(a1, a2), a3);
var outputArray = [];
for(var i = 0, finalLength = a1.length * a2.length * a3.length; i < finalLength; i++) {
outputArray[i] = a1[i % a1.length].toString() + a2[i % a2.length].toString() + a3[i % a3.length].toString();
}
But this is really just a stunt. Why avoid the loops? I can guess: You don't know in advance how many arrays you'll have. But it's still going to be a challenge.

Knowing position of a value under twodimensional Array

I have a SummaryData array as shown
var summaryData = [[0,100.34],[1,102.31],[2,131.08],[3,147.94],[4,172.55],[5,181.05],[6,180.08]];
My question is:
Is it possible to find out what the position of a value is?
(For example, how can I know where 147.94 is?) (I am expecting "3")
Update:
A more prototype-y way:
var result = summaryData.detect(function(item) { return item[1] === 147.94; });
alert(result[0]);
Or:
function getKey(arr, value) {
var key = null,
item;
for (var i = 0; i < arr.length && !key; i++) {
item = arr[i];
if (item[1] === value) {
key = i;
}
}
return key;
}
Usage:
var n = getKey(summaryData, 147.94); // returns 3.
At the risk of doing your homework for you...
var summaryData = [[0,100.34],[1,102.31],[2,131.08],[3,147.94],[4,172.55],[5,181.05],[6,180.08]];
function findPosition(value, dataArray) {
var a;
for (var i=0, iLen=dataArray.length; i<iLen; i++) {
a = dataArray[i];
for (var j=0, jLen=a.length; j<jLen; j++){
if (value == a[j]) {
return i + ',' + j;
}
}
}
}
alert(findPosition(131.08, summaryData)); // 2,1
The above returns the position of the first match.
Edit
I see now that you don't need to iterate over the second array, just look at the second value, so:
function findPosition(value, dataArray) {
var a;
for (var i=0, iLen=dataArray.length; i<iLen; i++) {
a = dataArray[i];
if (value == a[1]) {
return a[0];
}
}
}
alert(findPosition(131.08, summaryData)); //2
Or if the data format is always as specified and there may be thousands of values, then it may be much faster to do:
function findPosition(value, dataArray) {
var re = new RegExp('[^,],' + value);
var m = dataArray.join().match(re);
return m && m[0].replace(/,.*/,'');
// Or
// return m && m[0].split(',')[0];
}
function getPosition(candidate) {
var i = summaryData.length;
while (i) {
i -= 1;
if (summaryData[i][1] === candidate) {
return summaryData[i][0];
}
}
}

Categories

Resources