I have several numbers in an array
var numArr = [1, 3, 5, 9];
I want to cycle through that array and multiply every unique 3 number combination as follows:
1 * 3 * 5 =
1 * 3 * 9 =
1 * 5 * 9 =
3 * 5 * 9 =
Then return an array of all the calculations
var ansArr = [15,27,45,135];
Anyone have an elegant solution? Thanks in advance.
A general-purpose algorithm for generating combinations is as follows:
function combinations(numArr, choose, callback) {
var n = numArr.length;
var c = [];
var inner = function(start, choose_) {
if (choose_ == 0) {
callback(c);
} else {
for (var i = start; i <= n - choose_; ++i) {
c.push(numArr[i]);
inner(i + 1, choose_ - 1);
c.pop();
}
}
}
inner(0, choose);
}
In your case, you might call it like so:
function product(arr) {
p = 1;
for (var i in arr) {
p *= arr[i];
}
return p;
}
var ansArr = [];
combinations(
[1, 3, 5, 7, 9, 11], 3,
function output(arr) {
ansArr.push(product(arr));
});
document.write(ansArr);
...which, for the given input, yields this:
15,21,27,33,35,45,55,63,77,99,105,135,165,189,231,297,315,385,495,693
I think this should work:
var a = [1, 3, 5, 9];
var l = a.length;
var r = [];
for (var i = 0; i < l; ++i) {
for (var j = i + 1; j < l; ++j) {
for (var k = j + 1; k < l; ++k) {
r.push(a[i] * a[j] * a[k]);
}
}
}
Edit
Just for my own edification, I figured out a generic solution that uses loops instead of recursion. It's obvious downside is that it's longer thus slower to load or to read. On the other hand (at least on Firefox on my machine) it runs about twice as fast as the recursive version. However, I'd only recommend it if you're finding combinations for large sets, or finding combinations many times on the same page. Anyway, in case anybody's interested, here's what I came up with.
function combos(superset, size) {
var result = [];
if (superset.length < size) {return result;}
var done = false;
var current_combo, distance_back, new_last_index;
var indexes = [];
var indexes_last = size - 1;
var superset_last = superset.length - 1;
// initialize indexes to start with leftmost combo
for (var i = 0; i < size; ++i) {
indexes[i] = i;
}
while (!done) {
current_combo = [];
for (i = 0; i < size; ++i) {
current_combo.push(superset[indexes[i]]);
}
result.push(current_combo);
if (indexes[indexes_last] == superset_last) {
done = true;
for (i = indexes_last - 1; i > -1 ; --i) {
distance_back = indexes_last - i;
new_last_index = indexes[indexes_last - distance_back] + distance_back + 1;
if (new_last_index <= superset_last) {
indexes[indexes_last] = new_last_index;
done = false;
break;
}
}
if (!done) {
++indexes[indexes_last - distance_back];
--distance_back;
for (; distance_back; --distance_back) {
indexes[indexes_last - distance_back] = indexes[indexes_last - distance_back - 1] + 1;
}
}
}
else {++indexes[indexes_last]}
}
return result;
}
function products(sets) {
var result = [];
var len = sets.length;
var product;
for (var i = 0; i < len; ++i) {
product = 1;
inner_len = sets[i].length;
for (var j = 0; j < inner_len; ++j) {
product *= sets[i][j];
}
result.push(product);
}
return result;
}
console.log(products(combos([1, 3, 5, 7, 9, 11], 3)));
A recursive function to do this when you need to select k numbers among n numbers. Have not tested. Find if there is any bug and rectify it :-)
var result = [];
foo(arr, 0, 1, k, n); // initial call
function foo(arr, s, mul, k, n) {
if (k == 1) {
result.push(mul);
return;
}
var i;
for (i=s; i<=n-k; i++) {
foo(arr, i+1, mul*arr[i], k-1, n-i-1);
}
}
This is a recursive function.
First parameter is array arr.
Second parameter is integer s. Each call calculates values for part of the array starting from index s. Recursively I am increasing s and so array for each call is recursively becoming smaller.
Third parameter is the value that is being calculated recursively and is being passed in the recursive call. When k becomes 1, it gets added in the result array.
k in the size of combination desired. It decreases recursively and when becomes 1, output appended in result array.
n is size of array arr. Actually n = arr.length
var create3Combi = function(array) {
var result = [];
array.map(function(item1, index1) {
array.map(function(item2, index2) {
for (var i = index2 + 1; i < array.length; i++) {
var item3 = array[i];
if (item1 === item2 || item1 === item3 || item2 === item3 || index2 < index1) {
continue;
}
result.push([item1, item2, item3]);
}
});
});
return result;
};
var multiplyCombi = function(array) {
var multiply = function(a, b){
return a * b;
};
var result = array.map(function(item, index) {
return item.reduce(multiply);
});
return result;
}
var numArr = [1, 3, 5, 9];
// create unique 3 number combination
var combi = create3Combi(numArr); //[[1,3,5],[1,3,9],[1,5,9],[3,5,9]]
// multiply every combination
var multiplyResult = multiplyCombi(combi); //[15,27,45,135];
https://github.com/dankogai/js-combinatorics
Found this library. Tested to be working. Below is from the library document:
var Combinatorics = require('js-combinatorics');
var cmb = Combinatorics.combination(['a','b','c','d'], 2);
while(a = cmb.next()) console.log(a);
// ["a", "b"]
// ["a", "c"]
// ["a", "d"]
// ["b", "c"]
// ["b", "d"]
// ["c", "d"]
Using node, you can do this pretty easily using a library. First install bit-twiddle using npm:
npm install bit-twiddle
Then you can use it in your code like this:
//Assume n is the size of the set and k is the size of the combination
var nextCombination = require("bit-twiddle").nextCombination
for(var x=(1<<(k+1))-1; x<1<<n; x=nextCombination(x)) {
console.log(x.toString(2))
}
The variable x is a bit-vector where bit i is set if the ith element is contained in the combination.
Related
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
Example:
Given nums = [3, 2, 4], target = 6,
Because nums[1] + nums[2] = 2 + 4 = 6
return [1, 2].
Solution
var twoSum = function(nums, target) {
for(let i = 0; i <= nums.length; i++){
for(let j = 0; j <= nums.length; j++){
if(nums[i] + nums[j] == target){
return [i, j]
}
}
}
};
The code above works in other cases but not this one.
Expected result [1,2]
Output [0,0]
For instance, I've tried to use a different array of numbers and a different target and it works even if you change the order of the numbers
Example:
New array: [15, 7, 11, 2], target = 9,
Output: [1, 3].
I don't understand what is wrong with the solution and I hope that someone can explain. Thanks
You can use a very simple technique.
Basically, you can check if the difference of target & the element in the current iteration, exists in the array.
Assuming same index cannot be used twice
nums = [3, 2, 4], target = 6
nums[0] = 3
target = 6
diff = 6 - 3 = 3
nums.indexOf[3] = 0 // FAILURE case because it's the same index
// move to next iteration
nums[1] = 2
target = 6
diff = 6 - 2 = 4
nums.indexOf(4) = 2 // SUCCESS '4' exists in the array nums
// break the loop
Here's the accepted answer by the leetcode.
/**
* #param {number[]} nums
* #param {number} target
* #return {number[]}
*/
var twoSum = function(nums, target) {
for (let index = 0; index < nums.length; index++) {
const diff = target - nums[index];
const diffIndex = nums.indexOf(diff);
// "diffIndex !== index" takes care of same index not being reused
if (diffIndex !== -1 && diffIndex !== index) {
return [index, diffIndex];
}
}
};
Runtime: 72 ms, faster than 93.74% of JavaScript online submissions for Two Sum.
Memory Usage: 38.5 MB, less than 90.55% of JavaScript online submissions for Two Sum.
Can anybody help me in reducing the memory usage also?
I don't understand what is wrong with the solution and I hope that
someone can explain ?
Here you're both inner and outer loop start from 0th so in the case [3,2,4] and target 6 it will return [0,0] as 3 + 3 is equal to target, so to take care of same index element not being used twice created a difference of 1 between outer and inner loop
Make outer loop to start from 0th index and inner loop with value i+1
var twoSum = function(nums, target) {
for(let i = 0; i < nums.length; i++){
for(let j = i+1; j < nums.length; j++){
if(nums[i] + nums[j] == target){
return [i, j]
}
}
}
};
console.log(twoSum([15, 7, 11, 2],9))
console.log(twoSum([3, 2, 4],6))
we can solve this problem in O(n) by using the map/object.
We can maintain a map or object which will save all values with index and then we can iterate the array and find target-nums[i] for each value and will find that value in map/object.
let's see this by example:-
nums=[2,7,11,15]
target = 9;
then map/object will be
mm={
2 : 0,
7: 1,
11: 2,
15: 3
}
then for each value, we will find diff and find that diff in map/object.
for i=0 diff= 9-2=7 and mm.has(7) is true so our answer is 2 and 7.
for their index we can use mm.get(7) and i.
return [mm.get(7), i]
var twoSum = function(nums, target) {
let mm=new Map();
for(let i=0;i<nums.length;i++){
mm.set(nums[i],i);
}
let diff=0;
let j;
for(let i=0;i<nums.length;i++){
diff=target-nums[i];
if(mm.has(diff) && i!=mm.get(diff)){
j=mm.get(diff);
if(j>i){
return [i,j];
}else{
return [j,i];
}
}
}
};
Runtime: 76 ms, faster than 88.18% of JavaScript online submissions for Two Sum.
Memory Usage: 41.4 MB, less than 13.32% of JavaScript online submissions for Two Sum.
Your solution works as expected. For nums = [3, 2 ,4] and target = 6, [0, 0] is a valid solution for the outlined problem as nums[0] + nums[0] = 3 + 3 = 6.
If you need two different indices (In my understanding this is not required by the task) you can add an additional check for inequality (nums[i] + nums[j] == target && i != j).
var twoSum = function(nums, target) {
for(let i=0; i<nums.length; i++){
for(let j=i+1; j<nums.length; j++){
if(nums[j] === target - nums[i]){
return [i, j];
}
}
}
};
Here's a simple method to solve this problem and its efficient using different type of inputs using JavaScript.
Like with input of ([3,3], 6) and its expected output will be [0,1] and input like ([3,2,4], 6) with expected output will be [2,4]
var twoSum = function (nums, target) {
for (let i = 0; i <= nums.length; i++) {
for (let j = 0; j <= nums.length; j++) {
if (i !== j) {
if (nums[i] + nums[j] === target) {
return [i, j];
}
}
}
}
};
console.log(twoSum([3, 2, 4], 6));
var twoSum = function (nums, target) {
var len = nums.length;
for (var i = 0; i < len; i++) {
for (var j = i + 1; j < len; j++) {
if (nums[i] + nums[j] == target) {
return [i,j];
}
}
}
};
var twoSum = function(nums, target) {
for(var i=0;i<nums.length;i++){
for(var j=i+1;j<nums.length;j++){
temp = nums[i]+nums[j];
if(temp == target){
return [i,j]
}
}
}
};
console.log(twoSum([15, 7, 11, 2],9))
console.log(twoSum([3, 2, 4],6))
console.log(twoSum([3,3],6))
This works perfectly and the Runtime: 72 ms lesser than 84ms
Another efficient solution way to solve this problem with an O(n) time complexity is not using nested loops. I commented the steps, so JS developers can easy understand. Here is my solution using golang:
func twoSum(intArray []int, target int) []int {
response := []int{-1, -1} // create an array as default response
if len(intArray) == 0 { // return default response if the input array is empty
return response
}
listMap := map[int]int{} // create a Map, JS => listMap = new Map()
for index, value := range intArray { // for loop to fill the map
listMap[value] = index
}
for i, value := range intArray { // for loop to verify if the subtraction is in the map
result := target - value
if j, ok := listMap[result]; ok && i != j { // this verify if a property exists on a map in golang. In the same line we verify it i == j.
response[0] = i
response[1] = j
return response
}
}
return response
}
var twoSum = function(nums, target) {
var numlen = nums.length;
for(let i=0; i<=numlen; i++){
for(let j=i+1;j<numlen;j++){
var num1 = parseInt(nums[i]);
var num2 = parseInt(nums[j]);
var num3 = num1 + num2;
if(num3 == target){
return[i,j]
}
}
}
};
I suppose this could be a better solution. Instead of nesting loops, this provides a linear solution.
(PS: indexOf is kinda a loop too with O(n) complexity)
var twoSum = function (nums, target) {
const hm = {}
nums.forEach((num, i) => {
hm[target - num] = i
})
for (let i = 0; i < nums.length; i++) {
if(hm[nums[i]] !== undefined && hm[nums[i]] !== i) {
return ([hm[nums[i]], i])
}
}
};
var twoSum = function(nums, target) {
for (var i = 0; i < nums.length; i++)
{
if( nums.indexOf(target - nums[i]) !== -1)
{
return [i , nums.indexOf(target - nums[i])]
}
}
};
For clearity console a & b in inner for loop . This will give you clear insight
var twoSum = function(nums, target) {
var arr=[];
for(var a=0;a<nums.length;a++){
for(var b=1;b<nums.length;b++){
let c=nums[a]+nums[b];
if(c== target && a != b){
arr[0]=a;
arr[1]=b;
}
}
}
return arr;
};
My solution:
Create a Set
Then loop the array for retrieve all the differences between the target number minus all the elements in array. Insert only which are positive (as is a Set, duplicates will not be included).
Then iterates array again, now only compare if array elements is in the set, if yes take the index from i store in the index array and return it.
public static Object solution(int[] a, int target){
Set<Integer> s = new HashSet<>();
ArrayList<Integer> indexes = new ArrayList<Integer>();
for (int e : a){
Integer diff = new Integer(target - e);
if(diff>0){
s.add(diff);
}
}
int i = 0;
for (int e : a){
if(s.contains(e)){
indexes.add(i);
}
i++;
}
return indexes;
}
def twoSum(self, nums: List[int], target: int) -> List[int]:
for i in range(len(nums)):
comp = target - nums[i]
if comp in nums:
j = nums.index(comp)
if(i!=j):
return [i,j]
var twoSum = function(nums, target) {
for(let i = 0; i < nums.length; i++){
for(let j = i+1; j < nums.length; j++){
if(nums[i] + nums[j] == target){
return [i, j]
}
}
}
};
console.log(twoSum([15, 7, 11, 2],9))
console.log(twoSum([3, 2, 4],6))
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
indx =[]
for i in range(len(nums)):
for j in range(i+1,len(nums)):
if nums[j]==(target-nums[i]):
indx.append(i)
indx.append(j)
return indx
twoSummation = (numsArr, estTarget) => {
for(let index = 0; index < numsArr.length; index++){
for(let n = index+1; n < numsArr.length; n++){
if(numsArr[index] + numsArr[n] == estTarget){
return [index, n]
}
}
}
}
console.log(twoSummation([2,7,11,15], 9))
console.log(twoSummation([3,2,4], 6))
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
var twoSum = function(nums, target) {
for(var i=0;i<nums.length;i++){
for(var j=i+1;j<nums.length;j++){
temp = nums[i]+nums[j];
if(temp == target){
return [nums[i],nums[j]]
}
}
}
};
console.log(twoSum([15, 7, 11, 2],9))
console.log(twoSum([3, 2, 4],6))
console.log(twoSum([3,3],6))
</script>
</body>
</html>
Solution from my leetcode submission in Java. Top 75% in runtime, top 25% in memory. It is 0(n) however uses an external HashMap.
import java.util.HashMap;
class Solution {
public int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> numbers= new HashMap<Integer, Integer>();
for(int i=0; i<nums.length; i++){
int cur = nums[i];
numbers.put(cur, i);
}
for(int i=0; i<nums.length; i++){
//check map for diff of target - cur
int diff = target - nums[i];
if(numbers.containsKey(diff) && numbers.get(diff)!=i){
return new int[]{i, numbers.get(diff)};
}
}
return null;
}
}
Here is the idea:
var a = [4, 5, 6];
for (var m = 0; m < a[0]; m++)
for (var n = 0; n < a[1]; n++)
for (var p = 0; p < a[2]; p++)
console.log(`${m} + ${n} + ${p} = ${m+n+p}`);
Live Copy:
// This just tells the Stack Snippets in-snippet console not
// to throw away entries once it reaches a max (the default max
// is just the last 50 logs).
console.config({maxEntries: Infinity});
var a = [4, 5, 6];
for (var m = 0; m < a[0]; m++)
for (var n = 0; n < a[1]; n++)
for (var p = 0; p < a[2]; p++)
console.log(`${m} + ${n} + ${p} = ${m+n+p}`);
/* This just makes the console take up the full output area */
.as-console-wrapper {
max-height: 100% !important;
}
The code would get longer if the array a has more indexes. Could the code be shorten using Array.map or filter or a function?
We can do this without taking up massive amounts of memory, and fairly simply, by using recursion:
const process = (array, n, numbers) => {
if (n < array.length) {
// Not done yet, recurse once for each number at this level
const max = array[n];
for (let i = 0; i < max; ++i) {
process(array, n + 1, [...numbers, i]);
}
} else {
// Done with this level, process the numbers we got
console.log(`${numbers.join(" + ")} = ${numbers.reduce((s, e) => s + e)}`);
}
}
process([4, 5, 6], 0, []);
Live Copy, with cross-checking against your results to ensure the above does the same thing:
// This just tells the Stack Snippets in-snippet console not
// to throw away entries once it reaches a max (the default max
// is just the last 50 logs).
console.config({maxEntries: Infinity});
function thisSolution() {
const results = [];
const process = (array, n, numbers) => {
if (n < array.length) {
// Not done yet, recurse once for each number at this level
const max = array[n];
for (let i = 0; i < max; ++i) {
process(array, n + 1, [...numbers, i]);
}
} else {
// Done with this level, process the numbers we got
const result = numbers.reduce((s, e) => s + e);
results.push(result);
console.log(`${numbers.join(" + ")} = ${result}`);
}
}
process([4, 5, 6], 0, []);
return results;
}
function yourSolution() {
const results = [];
var a = [4, 5, 6];
for (var m = 0; m < a[0]; m++)
for (var n = 0; n < a[1]; n++)
for (var p = 0; p < a[2]; p++)
results.push(m + n + p);
return results;
}
const thisResult = thisSolution();
const yourResult = yourSolution();
if (thisResult.some((entry, index) => entry !== yourResult[index])) {
console.log("WRONG");
} else {
console.log("RIGHT");
}
/* This just makes the console take up the full output area */
.as-console-wrapper {
max-height: 100% !important;
}
This never goes deep into the stack (a.length + 1 stack frames, to be precise, so four in the example case). It builds up a number of temporary arrays (145 in the example case) that max out at a.length entries, releasing them as soon as they aren't needed anymore (a max of four are retained at any given time). Here's the quick and dirty metrics on that:
let maxStack = 0;
let stack = 0;
let totalArrays = 0;
let maxArrays = 0;
let arrays = 0;
// A wrapper for counting stack frames
const process = (...args) => {
if (++stack > maxStack) {
maxStack = stack;
}
const result = process2(...args);
--stack;
return result;
};
const process2 = (array, n, numbers) => {
if (n < array.length) {
// Not done yet, recurse once for each number at this level
const max = array[n];
for (let i = 0; i < max; ++i) {
++totalArrays;
if (++arrays > maxArrays) {
maxArrays = arrays;
}
process(array, n + 1, [...numbers, i]);
--arrays;
}
} else {
// Done with this level, process the numbers we got
//console.log(`${numbers.join(" + ")} = ${numbers.reduce((s, e) => s + e)}`);
}
}
process([4, 5, 6], 0, []);
++maxArrays; // To account for the one in the last argument above
++totalArrays; // "
console.log(`Max stack: ${maxStack}, max arrays: ${maxArrays}, total arrays: ${totalArrays}`);
It's easier if you break it down. First, you need to create a series per every element of your array.
let series = num => Array.from({ length: num + 1 }, (n, i) => i); //creates an array with nums from 0 to num.
That's the first part of your question. Then you need to do a cross product of your series.
Basically for two series [1, 2, 3] and [1, 2, 3, 4] you'll end up with a set of 12 elements:
[2, 3, 4, 5, 3, 4, 5, 6, 4, 5, 6, 7]
And for that you could do:
let crossProduct = (a1, a2) => Array.prototype.concat.call(...a1.map(n1 => a2.map(n2 => n1 + n2)));
Now all you need to do is have a crossProduct for every series.
let final = numbers.map(series).reduce(crossProduct);
And there you have it:
let numbers = [4, 5, 6];
let series = num => Array.from({ length: num + 1 }, (n, i) => i);
let crossProduct = (a1, a2) => Array.prototype.concat.call(...a1.map(n1 => a2.map(n2 => n1 + n2)));
let final = numbers.map(series).reduce(crossProduct);
console.log(final);
Edit: If it's from 0 to the number before (e.g. 4 is [0, 1, 2, 3]) then just take the + 1 in the series function.
2nd Edit: Less objects created for your crossProduct:
let crossProduct = (a1, a2) => {
let resultingSet = [];
for(let i = 0; i < a1.length; i++)
for(let j = 0; j < a2.length; j++)
resultingSet.push(a1[i] + a2[j]);
return resultingSet;
} //only one array is created
And if you want to avoid having the series on memory all the time:
let numbers = [4, 5, 6];
let series = function* (num){
for(let i = 0; i < num; i++){
yield i;
}
}
let crossProduct = (set, num) => {
let resultingSet = [];
for(let i = 0; i < set.length; i++){
for(let j of series(num)){
resultingSet.push(set[i] + j);
}
}
return resultingSet;
}
let final = numbers.reduce(crossProduct, [0]);
console.log(final);
Another solution that doesn't consume alot of memory and fairly efficient is by using an array that represnt the value of the indexes and update it each iteration.
first you create an array that represent in each element the amount of iterations you need to run in order to update the indexes respectively for example for this array [1, 2, 3 ,4 ,5] you will get:
[280, 140, 20, 5, 1] this means that index[0] will be updated each 280 iterations, index[1] will be updated each 140 iterations and so on..
totally you will run arr[n] * arr[n-1] * arr[n-2] * .... * arr[0] iterations as you did with ordinary nested for loop.
var arr = [1, 2, 7, 4, 5];
var indexes = Array.from({length: arr.length}, () => 0);
iterationsPerElement = arr.map((_, i) => arr.slice(i+1).reduce((acc, elem) => acc * elem, 1));
var totalIterations = iterationsPerElement[0] * arr[0];
for(var iteration = 1; iteration <= totalIterations; iteration++) {
// sum those indexes
console.log(`sum = ${indexes.reduce((acc, index) => acc + index, 0)}`);
// update indexes
for(i = 0; i < indexes.length; i++) {
if(iteration % iterationsPerElement[i] == 0) {
indexes[i]++;
// empty the indexes on the right
for(var j=i+1; j <indexes.length; j++) {
indexes[j] = 0;
}
}
}
}
I need code that takes an array, counts the number of elements in it and returns a set of arrays, each displaying a different combination of elements. However, the starting element should be the same for each array. Better to explain with a few examples:
var OriginalArray = ['a','b','c']
should return
results: [['a','b','c'], ['a','c','b']]
or for example:
var originalArray = ['a','b','c','d']
should return
[['a','b','c','d'], ['a','b','d', 'c'], ['acbd', 'acdb', 'adbc', 'adcb']]
Again note how the starting element, in this case 'a' should always be the starting element.
You can use Heap's algorithm for permutations and modify it a bit to add to result only if first element is equal to first element of original array.
var arr = ['a', 'b', 'c', 'd']
function generate(data) {
var r = [];
var first = data[0];
function swap(x, y) {
var tmp = data[x];
data[x] = data[y];
data[y] = tmp;
}
function permute(n) {
if (n == 1 && data[0] == first) r.push([].concat(data));
else {
for (var i = 0; i < n; i++) {
permute(n - 1);
swap(n % 2 ? 0 : i, n - 1);
}
}
}
permute(data.length);
return r;
}
console.log(generate(arr))
You have to do a .slice(1) to feed the rest of the array to a permutations function. Then you can use .map() to stick the first item to the front of each array in the result of permutations function.
If you will do this job on large sets and frequently then the performance of the permutations function is important. The following uses a dynamical programming approach and to my knowledge it's the fastest.
function perm(a){
var r = [[a[0]]],
t = [],
s = [];
if (a.length <= 1) return a;
for (var i = 1, la = a.length; i < la; i++){
for (var j = 0, lr = r.length; j < lr; j++){
r[j].push(a[i]);
t.push(r[j]);
for(var k = 1, lrj = r[j].length; k < lrj; k++){
for (var l = 0; l < lrj; l++) s[l] = r[j][(k+l)%lrj];
t[t.length] = s;
s = [];
}
}
r = t;
t = [];
}
return r;
}
var arr = ['a','b','c','d'],
result = perm(arr.slice(1)).map(e => [arr[0]].concat(e));
console.log(JSON.stringify(result));
Starting with this initial 2D array:
var initialArray = [[2,3],[6,7],[4,5],[1,2],[5,6],[2,3]];
I need to create this 3D array programmatically:
var fullArray = [
[[2,3],[6,7],[4,5],[1,2],[5,6],[2,3]],
[[3,4],[0,1],[5,6],[2,3],[6,7],[3,4]],
[[4,5],[1,2],[6,7],[3,4],[0,1],[4,5]],
[[5,6],[2,3],[0,1],[4,5],[1,2],[5,6]],
[[6,7],[3,4],[1,2],[5,6],[2,3],[6,7]],
[[0,1],[4,5],[2,3],[6,7],[3,4],[0,1]],
[[1,2],[5,6],[3,4],[0,1],[4,5],[1,2]],
[[2,3],[6,7],[4,5],[1,2],[5,6],[2,3]],
[[3,4],[0,1],[5,6],[2,3],[6,7],[3,4]],
[[4,5],[1,2],[6,7],[3,4],[0,1],[4,5]],
[[5,6],[2,3],[0,1],[4,5],[1,2],[5,6]]
];
See the pattern?
On each pair, the [0] position should increment to 6 (from any starting number <= 6) and then reset to 0 and then continue incrementing. Similarly, the [1] position should increment to 7 (from any starting number <= 7) and then reset to 1 and then continue incrementing.
In this example, there are 10 2D arrays contained in the fullArray. However, I need this number to be a variable. Something like this:
var numberOf2DArraysInFullArray = 12;
Furthermore, the initial array should be flexible so that initialArray values can be rearranged like this (but with the same iteration follow-through rules stated above):
var initialArray = [[6,7],[2,3],[5,6],[4,5],[1,2],[6,7]];
Any thoughts on how to programmatically create this structure?
Stumped on how to gracefully pull this off.
Feedback greatly appreciated!
Here's a solution, I've separated the methods, and I made it so if instead of pairs it's an N size array and you want the [2] to increase up to 8 and reset to 2, if that's not needed you can simplify the of the loop for(var j = 0; j < innerArray.length; j++)
var initialArray = [[2,3],[6,7],[4,5],[1,2],[5,6],[2,3]];
var create3DArray = function(array, size){
var newArray = [initialArray];
for(var i = 0; i < size; i++)
{
newArray.push(getNextArrayRow(newArray[i]));
}
return newArray;
}
var getNextArrayRow = function(array){
var nextRow = [];
for(var i = 0; i < array.length; i++)
{
var innerArray = array[i];
var nextElement = [];
for(var j = 0; j < innerArray.length; j++)
{
var value = (innerArray[j] + 1) % (7 + j);
value = value === 0 ? j : value;
nextElement.push(value);
}
nextRow.push(nextElement);
}
return nextRow;
}
console.log(create3DArray(initialArray,3));
Note, the results from running the snippet are a bit difficult to read...
var initialArray = [[2,3],[6,7],[4,5],[1,2],[5,6],[2,3]];
var numOfArrays = 10;
// get a range array [0, 1, 2, ...]
var range = [];
for (var i = 0; i < numOfArrays; i++) {
range.push(i);
}
var result = range.reduce(function(prev, index) {
if (index == 0) {
return prev;
}
prev.push(transformArray(prev[index - 1]));
return prev;
}, [initialArray])
console.log(result);
function transformArray(arr) {
return arr.map(transformSubArray)
}
function transformSubArray(arr) {
return arr.map(function(val) {
return val == 7 ? 0 : val + 1;
})
}
Here's a pretty simple functional-ish implementation
I am trying to count the number of permutations that do not contain consecutive letters. My code passes tests like 'aabb' (answer:8) and 'aab' (answer:2), but does not pass cases like 'abcdefa'(my answer: 2520; correct answer: 3600). Here's my code:
function permAlone(str) {
var totalPerm = 1;
var result = [];
//assign the first letter
for (var i = 0; i < str.length; i++) {
var firstNum = str[i];
var perm = firstNum;
//create an array from the remaining letters in the string
for (var k = 0; k < str.length; k++) {
if (k !== i) {
perm += str[k];
}
}
//Permutations: get the last letter and change its position by -1;
//Keep changing that letters's position by -1 until its index is 1;
//Then, take the last letter again and do the same thing;
//Keep doing the same thing until the total num of permutations of the number of items in the string -1 is reached (factorial of the number of items in the string -1 because we already established what the very first letter must be).
var permArr = perm.split("");
var j = permArr.length - 1;
var patternsLeft = totalNumPatterns(perm.length - 1);
while (patternsLeft > 0) {
var to = j - 1;
var subRes = permArr.move(j, to);
console.log(subRes);
if (noDoubleLettersPresent(subRes)) {
result.push([subRes]);
}
j -= 1;
if (j == 1) {
j = perm.length - 1;
}
patternsLeft--;
}
}
return result.length;
}
Array.prototype.move = function(from, to) {
this.splice(to, 0, (this.splice(from, 1))[0]);
return this.join("");
};
function totalNumPatterns(numOfRotatingItems) {
var iter = 1;
for (var q = numOfRotatingItems; q > 1; q--) {
iter *= q;
}
return iter;
}
function noDoubleLettersPresent(str) {
if (str.match(/(.)\1/g)) {
return false;
} else {
return true;
}
}
permAlone('abcdefa');
I think the problem was your permutation algorithm; where did you get that from? I tried it with a different one (after Filip Nguyen, adapted from his answer to this question) and it returns 3600 as expected.
function permAlone(str) {
var result = 0;
var fact = [1];
for (var i = 1; i <= str.length; i++) {
fact[i] = i * fact[i - 1];
}
for (var i = 0; i < fact[str.length]; i++) {
var perm = "";
var temp = str;
var code = i;
for (var pos = str.length; pos > 0; pos--) {
var sel = code / fact[pos - 1];
perm += temp.charAt(sel);
code = code % fact[pos - 1];
temp = temp.substring(0, sel) + temp.substring(sel + 1);
}
console.log(perm);
if (! perm.match(/(.)\1/g)) result++;
}
return result;
}
alert(permAlone('abcdefa'));
UPDATE: In response to a related question, I wrote an algorithm which doesn't just brute force all the permutations and then skips the ones with adjacent doubles, but uses a logical way to only generate the correct permutations. It's explained here: Permutations excluding repeated characters and expanded to include any number of repeats per character here: Generate all permutations of a list without adjacent equal elements
I agree with m69, the bug seems to be in how you are generating permutations. I got 3600 for 'abcdefa' by implementing a different algorithm for generating permutations. My solution is below. Since it uses recursion to generate the permutations the solution is not fast, however you may find the code easier to follow, if speed is not important.
The reason for having a separate function to generate the array index values in the permutations was to verify that the permutation code was working properly. Since there are duplicate values in the input strings it's harder to debug issues in the permutation algorithm.
// Simple helper function to compute all permutations of string indices
function permute_indices_helper(input) {
var result = [];
if (input.length == 0) {
return [[]];
}
for(var i = 0; i < input.length; i++) {
var head = input.splice(i, 1)[0];
var tails = permute_indices_helper(input);
for (var j = 0; j < tails.length; j++) {
tails[j].splice(0, 0, head);
result.push(tails[j]);
}
input.splice(i, 0, head); // check
}
return result;
};
// Given an array length, generate all permutations of possible indices
// for array of that length.
// Example: permute_indices(2) generates:
// [[0,1,2], [0,2,1], [1,0,2], ... , [2, 0, 1]]
function permute_indices(array_length) {
var result = [];
for (var i = 0; i < array_length; i++) {
result.push(i);
}
return permute_indices_helper(result);
}
// Rearrange letters of input string according to indices.
// Example: "car", [2, 1, 0]
// returns: "rac"
function rearrange_string(str, indices) {
var result = "";
for (var i = 0; i < indices.length; i++) {
var string_index = indices[i];
result += str[string_index];
}
return result;
}
function permAlone(str) {
var result = 0;
var permutation_indices = permute_indices(str.length);
for (var i = 0; i < permutation_indices.length; i++) {
var permuted_string = rearrange_string(str, permutation_indices[i]);
if (! permuted_string.match(/(.)\1/g)) result++;
}
return result;
}
You can see a working example on JSFiddle.