I'm trying to create a Boggle Solver program and I am having errors with my depth-first-search function. After I iterate through the 'visited' array using a for-loop, my function should return and start going through my trie again. Instead, it continues to print the value that is found in the visited array. The code is displayed below.
// Sample Boggle Dictionary
var boggle_dxctionary = ['apple', 'pickle', 'side',
'sick', 'moo', 'cat',
'cats', 'man', 'super',
'antman', 'godzilla', 'dog',
'dot', 'sine', 'cos',
'signal', 'bitcoin', 'cool',
'kick', 'zapper'
];
// Sample Boggle Board
var boggle_board = [
['c', 'n', 't', ],
['d', 'a', 't', ],
['o', 'o', 'm', ],
];
var column_length = boggle_board[0].length;
var row_length = boggle_board.length;
var trie_node = {
'valid': false,
'next': {}
};
var neighbors_delta = [
[-1, -1],
[-1, 0],
[-1, 1],
[0, -1],
[0, 1],
[1, -1],
[1, 0],
[1, 1],
];
function generate_trie(word, node)
{
if (!(word))
{
return;
}
if ((word[0] in node) == false)
{
node[word[0]] = { 'valid': (word.length == 1),'next': {}};
}
generate_trie(word.slice(1, ), node[word[0]]);
}
function build_trie(boggle_dxct, trie) {
for (var word = 0; word < boggle_dxct.length; word++) {
generate_trie(boggle_dxct[word], trie);
}
return trie;
}
function get_neighbors(row, column)
{
var neighbors = [];
for (var neighbor = 0; neighbor < neighbors_delta.length; neighbor++)
{
var new_row = row + neighbors_delta[neighbor][0];
var new_column = column + neighbors_delta[neighbor][1];
if (new_row >= row_length || new_column >= column_length || new_row < 0 || new_column < 0)
{
continue;
}
neighbors.push([new_row, new_column]);
}
return neighbors;
}
function depth_first_search(row, column, visited, trie, current_word, found_words, board)
{
var row_column_pair = [row, column];
for (var i = 0; i < visited.length; i++) # Infinity loop error
{
var a = visited[i][0];
var b = visited[i][1];
if (row == a && column == b)
{
console.log(a,b);
return;
}
}
var letter = board[row][column];
visited.push(row_column_pair);
if (letter in trie)
{
current_word = current_word + letter;
console.log(current_word)
if (trie[letter]['valid'])
{
console.log("Found word", current_word, "at", row_column_pair);
found_words.push(current_word);
//console.log(visited);
}
var neighbors = get_neighbors(row, column);
for (n = 0; n < neighbors.length; n++)
{
depth_first_search(neighbors[n][0], neighbors[n][1], visited.slice(0), trie[letter], current_word, found_words, board);
}
}
}
function main(trie_node, board) {
trie_node = build_trie(boggle_dxctionary, trie_node);
var found_words = [];
for (r = 0; r < row_length; r++) {
for (c = 0; c < column_length; c++)
{
var visited = [];
depth_first_search(r, c, visited, trie_node, '', found_words, board);
}
}
console.log(found_words);
}
main(trie_node, boggle_board);
The problem in your code is in depth_first_search where you did not define n as a local variable, but as implicit global variable.
Your code will run fine when you replace this:
for (n = 0; n < neighbors.length; n++)
with:
for (var n = 0; n < neighbors.length; n++)
NB: I assume there was a little typo in the input, where "moo" should really be "mood".
I suggest to use a more simplified trie without overhead.
Then iterate the given board and check the actual position and by handing over the root node of trie.
A word is found if end property exists.
function check(i, j, t, found = '') {
const letter = board[i][j];
if (!t[letter]) return;
found += letter
if (t[letter].end) {
words.push(found);
}
for (let [x, y] of neighbors) {
if (i + x < 0 || i + x >= rows || j + y < 0 || j + y >= cols) continue;
check(i + x, j + y, t[letter], found);
}
}
const
dictionary = ['apple', 'pickle', 'side', 'sick', 'moo', 'cat', 'cats', 'man', 'super', 'antman', 'godzilla', 'dog', 'dot', 'sine', 'cos', 'signal', 'bitcoin', 'cool', 'kick', 'zapper'],
board = [['c', 'n', 't'], ['d', 'a', 't'], ['o', 'o', 'm']],
rows = board.length,
cols = board[0].length,
neighbors = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]],
trie = dictionary.reduce((trie, word) => {
[...word].reduce((t, c) => t[c] = t[c] || {}, trie).end = true;
return trie;
}, {}),
words = [];
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
check(i, j, trie);
}
}
console.log(words);
console.log(trie);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Related
I am trying to generate sprial matrix in javascript.
question
Given an integer A, generate a square matrix filled with elements from 1 to A^2 in spiral order.
input : 3
[ [ 1, 2, 3 ],
[ 8, 9, 4 ],
[ 7, 6, 5 ] ]
when input is 4
[ [1, 2, 3, 4],
[12, 13, 14, 5],
[11, 16, 15, 6],
[10, 9, 8, 7] ]
my approach is to create 2d array with 0 value and after that they will fill values.
let generateMatrix = function(A) {
let arr = [], counter = 1;
for (let i = 0; i < A; i++) {
let items = []
for (let j = 0; j < A; j++) {
items.push(0)
}
arr.push(items)
}
var spiralMatrix = function(arr) {
if (arr.length > 1) {
for (let i = 0; i < arr[0].length; i++) {
arr[0][i] = counter++;
}
}
return arr
}
return spiralMatrix(arr)
}
console.log(generateMatrix(2))
You could take loops for each edges and loop until no more ranges are avaliable.
function spiral(length) {
var upper = 0,
lower = length - 1,
left = 0,
right = length - 1,
i = 0,
j = 0,
result = Array.from({ length }, _ => []),
value = 1;
while (true) {
if (upper++ > lower) break;
for (; j < right; j++) result[i][j] = value++;
if (right-- < left) break;
for (; i < lower; i++) result[i][j] = value++;
if (lower-- < upper) break;
for (; j > left; j--) result[i][j] = value++;
if (left++ > right) break;
for (; i > upper; i--) result[i][j] = value++;
}
result[i][j] = value++;
return result;
}
var target = document.getElementById('out'),
i = 10;
while (--i) target.innerHTML += spiral(i).map(a => a.map(v => v.toString().padStart(2)).join(' ')).join('\n') + '\n\n';
<pre id="out"></pre>
This bit of code should do what you are trying to.
// This is your Editor pane. Write your JavaScript hem and
// use the command line to execute commands
let generateMatrix = function(A) {
let arr = [],
counter = 1;
for (let i = 0; i < A; i++) {
let items = [];
for (let j = 0; j < A; j++) {
items.push(0);
}
arr.push(items);
}
var spiralMatrix = function(arr) {
let count = 1;
let k = 0; // starting row
let m = arr.length; // ending row
let l = 0; // starting column
let n = arr[0].length; //ending column
while (k < m && l < n) {
// top
for (var i = l; i < n; i++) {
arr[k][i] = count;
count++;
}
k++;
// right
for (var i = k; i < m; i++) {
arr[i][n - 1] = count;
count++;
}
n--;
// bottom
if (k < m) {
for (var i = n - 1; i >= l; i--) {
arr[m - 1][i] = count;
count++;
}
m--;
}
// left
if (l < n) {
for (var i = m - 1; i >= k; i--) {
arr[i][l] = count;
count++;
}
l++;
}
}
return arr;
};
return spiralMatrix(arr);
};
console.log(generateMatrix(4));
This is in some ways the reverse of an answer I gave to another question. We can recursively build this up by slicing out the first row and prepending it to the result of rotating the result of a recursive call on the remaining numbers:
const reverse = a =>
[...a] .reverse ();
const transpose = m =>
m [0] .map ((c, i) => m .map (r => r [i]))
const rotate = m =>
transpose (reverse (m))
const makeSpiral = (xs, rows) =>
xs .length < 2
? [[... xs]]
: [
xs .slice (0, xs .length / rows),
... rotate(makeSpiral (xs .slice (xs .length / rows), xs.length / rows))
]
const range = (lo, hi) =>
[...Array (hi - lo + 1)] .map ((_, i) => lo + i)
const generateMatrix = (n) =>
makeSpiral (range (1, n * n), n)
console .log (generateMatrix (4))
A sharp eye will note that rotate is different here from the older question. transpose (reverse (m)) returns a clockwise rotated version of the input matrix. reverse (transpose (m)) returns a counter-clockwise rotated one. Similarly, here we rotate the result of the recursive call before including it; whereas in the other question we recurse on the rotated version of the matrix. Since we're reversing that process, it should be reasonably clear why.
The main function is makeSpiral, which takes an array and the number of rows to spiral it into and returns the spiraled matrix. (If rows is not a factor of the length of the array, the behavior might be crazy.) generateMatrix is just a thin wrapper around that to handle your square case by generating the initial array (using range) and passing it to makeSpiral.
Note how makeSpiral works with rectangles other than squares:
makeSpiral ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 2) //=>
// [
// [ 1, 2, 3, 4, 5, 6],
// [12, 11, 10, 9, 8, 7]
// ]
makeSpiral ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 3) //=>
// [
// [ 1, 2, 3, 4],
// [10, 11, 12, 5],
// [ 9, 8, 7, 6]
// ]
makeSpiral ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 4) //=>
// [
// [ 1, 2, 3],
// [10, 11, 4],
// [ 9, 12, 5],
// [ 8, 7, 6]
// ]
makeSpiral ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 6) //=>
// [
// [ 1, 2],
// [12, 3],
// [11, 4],
// [10, 5],
// [ 9, 6],
// [ 8, 7]
// ]
The other functions -- range, reverse, transpose, and rotate -- are general purpose utility functions for working with arrays or matrices.
Here's one solution.
I keep the current "moving direction" in dx and dy, such that the next matrix element indices are given by x+dx and y+dy.
If the next item is already filled or is out of bounds, I change this direction clockwise. Otherwise, I fill it with the next value.
const size = 6;
const matrix = Array(size).fill().map(() => Array(size).fill(0));
let x = -1;
let y = 0;
let dx = 1;
let dy = 0;
function changeDirection() {
if (dx === 1) {
dx = 0;
dy = 1;
} else if (dy === 1) {
dy = 0;
dx = -1;
} else if (dx === -1) {
dx = 0;
dy = -1;
} else {
dx = 1;
dy = 0;
}
}
for (let i = 0; i < size * size; i++) {
const yNext = y + dy;
const xNext = x + dx;
const nextRow = matrix[yNext] || [];
const nextItemContent = nextRow[xNext];
if (nextItemContent === undefined || nextItemContent > 0) {
changeDirection();
i--;
continue;
}
y = yNext;
x = xNext;
matrix[y][x] = i + 1;
}
const result = document.getElementById('result');
matrix.forEach(row => {
row.forEach(value => {
result.innerHTML += value.toString().padStart(3);
});
result.innerHTML += '\n';
});
<pre id="result"></pre>
I'm calculating the index, each number should go in a linear array
console.clear();
Array.prototype.range = function(a, b, step) {
step = !step ? 1 : step;
b = b / step;
for(var i = a; i <= b; i++) {
this.push(i*step);
}
return this;
};
const spiral = function(dimen) {
"use strict";
const dim = dimen;
const dimw = dim;
const dimh = dim;
var steps = [1, dimh, -1, -dimh];
var stepIndex = 0;
var count = 1;
var countMax = dimw
var dec = 0
var index = 0;
var arr = [];
arr = arr.range(1, dimh * dimw)
const newArr = arr.reduce((coll, x, idx) => {
index += steps[stepIndex]
coll[index-1] = idx+1;
if (count === countMax) {count = 0; stepIndex++; dec++;}
if (dec === 1) {dec = -1; countMax--}
if (stepIndex == steps.length) {stepIndex = 0}
count++;
return coll;
}, []);
var ret = []
while (newArr.length) {
ret.push(newArr.splice(0,dimw))
}
return ret
}
console.log(spiral(3))
console.log(spiral(4))
console.log(spiral(5))
var n=14; // size of spiral
var s=[]; // empty instruction string
function emp() {} // no move
function xpp() {xp++;} // go right
function xpm() {xp--;} // go left
function ypp() {yp++;} // go down
function ypm() {yp--;} // go up
var r=[xpp,ypp,xpm,ypm]; // instruction set
s.push(emp); // push 'no move' (used for starting point)
var c=n-1;
while (c-->0) s.push(r[0]); // push first line - uses a different rule
for (var i=1;i<2*n-1;i++) { // push each leg
c=Math.floor((2*n-i)/2);
while (c-->0) s.push(r[i%4]);
}
var sp=new Array(n); // spiral array
for (var i=0;i<n;i++) sp[i]=new Array(n);
var xp=0; // starting position
var yp=0;
for (var i=0;i<n*n;i++) {
s[i](); // execute next instruction
sp[yp][xp]=i+1; // update array
}
for (var i=0;i<n;i++) console.log(sp[i].toString()); // log to console
This code makes a macro of functions to generate a run sequence, for example:
'right4, down4, left4, up3, right3, down2, left2, up1, right1
and then implements it.
Here is a solution to Spiral Matrix from leetcode, maybe this can help
https://leetcode.com/problems/spiral-matrix/
var spiralOrder = function(matrix) {
if (matrix.length == 0) {
return [];
}
let result = [];
let rowStart = 0;
let rowEnd = matrix.length - 1;
let colStart = 0;
let colEnd = matrix[0].length - 1;
while (true) {
// top
for (let i = colStart; i <= colEnd; i++) {
result.push(matrix[rowStart][i]);
}
rowStart++;
if (rowStart > rowEnd) {
return result;
}
// right
for (let i = rowStart; i <= rowEnd; i++) {
result.push(matrix[i][colEnd]);
}
colEnd--;
if (colEnd < colStart) {
return result;
}
// bottom
for (let i = colEnd; i >= colStart; i--) {
result.push(matrix[rowEnd][i]);
}
rowEnd--;
if (rowEnd < rowStart) {
return result;
}
// left
for (let i = rowEnd; i >= rowStart; i--) {
result.push(matrix[i][colStart]);
}
colStart++;
if (colStart > colEnd) {
return result;
}
}
return result;
};
console.log(
spiralOrder([[2, 3, 4], [5, 6, 7], [8, 9, 10], [11, 12, 13], [14, 15, 16]])
);
console.log(spiralOrder([[7], [9], [6]]));
console.log(spiralOrder([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]));
console.log(spiralOrder([[1, 2, 3], [4, 5, 6], [7, 8, 9]]));
Here's my answer using only one for loop -
function matrix(n) {
const arr = [];
let row = 0;
let column = 0;
let counter = 1;
let edge = n - 1;
let leftToRightRow = false;
let topToBottomCol = false;
let rightToLeftRow = false;
let bottomToTopCol = false;
for (i = 0; i < n * n; i++) {
if (column <= edge && !leftToRightRow) {
if (!Array.isArray(arr[row])) {
arr[row] = []; // if array is not present at this index, then insert one
}
arr[row][column] = counter;
if (column == edge) {
row = row + 1;
leftToRightRow = true;
} else {
column = column + 1;
}
counter = counter + 1;
} else if (column === edge && !topToBottomCol) {
if (!Array.isArray(arr[row])) {
arr[row] = []; // if array is not present at this index, then insert one
}
arr[row][column] = counter;
if (row === edge) {
column = column - 1;
topToBottomCol = true;
} else {
row = row + 1;
}
counter = counter + 1;
} else if (column >= 0 && !rightToLeftRow) {
arr[row][column] = counter;
if (column === 0) {
row = row - 1;
rightToLeftRow = true;
} else {
column = column - 1;
}
counter = counter + 1;
} else if (row >= n - edge && !bottomToTopCol) {
arr[row][column] = counter;
if (row === n - edge) {
column = column + 1;
bottomToTopCol = true;
//setting these to false for next set of iteration
leftToRightRow = false;
topToBottomCol = false;
rightToLeftRow = false;
edge = edge - 1;
} else {
row = row - 1;
}
counter = counter + 1;
}
}
return arr;
}
Solution is implemented in C++, but only logic matter then you can do it in any language:
vector<vector<int> > Solution::generateMatrix(int A) {
vector<vector<int>> result(A,vector<int>(A));
int xBeg=0,xEnd=A-1;
int yBeg=0,yEnd=A-1;
int cur=1;
while(true){
for(int i=yBeg;i<=yEnd;i++)
result[xBeg][i]=cur++;
if(++xBeg>xEnd) break;
for(int i=xBeg;i<=xEnd;i++)
result[i][yEnd]=cur++;
if(--yEnd<yBeg) break;
for(int i=yEnd;i>=yBeg;i--)
result[xEnd][i]=cur++;
if(--xEnd<xBeg) break;
for(int i=xEnd;i>=xBeg;i--)
result[i][yBeg]=cur++;
if(++yBeg>yEnd) break;
}
return result;
}
Solition in c#:
For solving this problem we use loops for each moving directions
public IList<int> SpiralOrder(int[][] matrix) {
var result = new List<int>();
var n = matrix[0].Length;
var m = matrix.Length;
var i = 0;
var j = 0;
var x = 0;
var y = 0;
while (true)
{
//left to right moving:
while (x <= n - 1 - i)
{
result.Add(matrix[y][x]);
x++;
}
if (result.Count == n * m)
return result;
x--;y++;
//up to down moving:
while (y <= m - 1 - j)
{
result.Add(matrix[y][x]);
y++;
}
if (result.Count == n * m)
return result;
y--;x--;
//right to left moving:
while (x >= j)
{
result.Add(matrix[y][x]);
x--;
}
if (result.Count == n * m)
return result;
x++;y--;
//down to up moving:
while (y > j)
{
result.Add(matrix[y][x]);
y--;
}
if (result.Count == n * m)
return result;
y++;x++;
i++;
j++;
}
}
I am trying to find horizontalWord string in two-dimensional array. verticalWord works fine , but I am having trouble with the horizontalWord string. Let me know if you have any ideas.
let matrix = [
[0, 'r', 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
['a', 'p', 'p', 'l', 'e'],
[0, 0, 0, 0, 0]
]
function isInMatrix(matrix, word) {
for (let j = 0; j < matrix[0].length; j++) {
let verticalWord = ''
let horizontalWord = ''
for (let i = 0; i < matrix.length; i++) {
verticalWord += matrix[i][j]
}
for (let k = 0; k < matrix[0].length; k++) {
horizontalWord += matrix[j][k]
}
if ((verticalWord.includes(word)) ||
(verticalWord.split('').reverse().join('').includes(word)) ||
(horizontalWord.includes(word)) ||
(horizontalWord.split('').reverse().join('').includes(word))) return true
}
return false
}
console.log(isInMatrix(matrix, 'apple'))
Your loops are incorrect, you are only checking the first 5 rows of the matrix
for (let j = 0; j < matrix[0].length; j++) {
use (let j = 0; j < matrix.length; j++)
You could get a transpose of the matrix by using nested map
Then check if some of the inner arrays have the given word using join and includes. Check this for both the matrix and it's transpose to test horizontally and vertically
let input = [
[0, 'r', 0, 0, 0, 0, 0],
[0, 'e', 0, 0, 0, 0, 0],
[0, 'd', 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 'a', 'p', 'p', 'l', 'e', 0]
]
function isInArray(matrix, word) {
let transpose = matrix[0].map((a, i) => matrix.map(b => b[i]));
return matrix.some(a => a.join('').includes(word))
|| transpose.some(a => a.join('').includes(word))
}
console.log(isInArray(input, "apple"))
console.log(isInArray(input, "red"))
console.log(isInArray(input, "orange"))
function isInBoard(board, word) {
if (word === '') return false;
if (board.length < 1 || board[0].length < 1) return false;
const start = findStartingPoint(board, word[0]);
if (start.length < 1) return false;
for (let S of start) {
if (findPathList(board, word.slice(1), S, [])) return true;
}
return false;
}
function findPathList(B, W, S, L) {
L.push(S.join(':'));
if (!W) return true;
let r = S[0], c = S[1], rows = B.length, cols = B[0].length;
const next = [];
if (r-1 >= 0 && B[r-1][c] === W[0] && !L.includes((r-1)+':'+c)) next.push([r-1, c]);
if (r+1 < rows && B[r+1][c] === W[0] && !L.includes((r+1)+':'+c)) next.push([r+1, c]);
if (c-1 >= 0 && B[r][c-1] === W[0] && !L.includes(r+':'+(c-1))) next.push([r, c-1]);
if (c+1 < cols && B[r][c+1] === W[0] && !L.includes(r+':'+(c+1))) next.push([r, c+1]);
for (let N of next) {
const found = findPathList(B, W.slice(1), N, [...L]);
if (found) {
return true;
}
}
return false;
}
function findStartingPoint(board, s) {
const answer = [];
for (let r = 0; r < board.length; r++) {
let index = -1;
while(true) {
index = board[r].indexOf(s, index+1);
if (index >= 0) answer.push([r, index]);
else break;
}
}
return answer;
}
board = [ ['A','B','C','E'],['S','F','C','S'],['A','D','E','E'] ];
words = ["ABCCED", "SEE", "ABCB"];
// true, true, false
for (let word of words) console.log(isInBoard(board, word));
board = [ ["A","B","C","E"],["S","F","E","S"],["A","D","E","E"] ];
word = "ABCESEEEFS";
console.log(isInBoard(board, word)); // true
I was set the task to create an array of all permutations/ 4 digit numbers of a given array of numbers: [1,2,3,4,5,6,7,8,9]. There can be no repeats of digits as each value must be unique. Below is my solution but I am struggling to apply recursion to the process. I want it to be adaptable so if conditions changed i.e. the function must produce all combinations of 5 digit numbers or even 6 digit, as little code needs to be changed and adding recursion would allow for this easily. As you can see below the code does work but if conditions changed this would require even more nested for loops. I am looking for a recursive solution. This does not seem like a good solution but any advice would be most grateful. I have seen a lot online about creating solutions where 4P4 or 5P5 but not 9P5 kind of styles. I tried to apply heap's algorithm but to no success.
function arrayCreate((availableNumbers, userNumberArray)) {
var possibleValues = []; //empty array to house all the possible combination of values that the user could enter i.e. 1234 to 9876
var numberOfPermutations = (factorial(availableNumbers.length) / factorial(availableNumbers.length - userNumberArray.length));
var adding = true;
var firstDigit, secondDigit, thirdDigit, forthDigit =0;
var possibleDigitValue = "";
while (adding === true) {
for (var i = 0; i < availableNumbers.length; i++) {
firstDigit = availableNumbers[i];
availableNumbers.splice(i, 1);
for (var j = 0; j < availableNumbers.length; j++) {
secondDigit = availableNumbers[j];
availableNumbers.splice(j, 1);
for (var k = 0; k < availableNumbers.length; k++) {
thirdDigit = availableNumbers[k]
availableNumbers.splice(k, 1);
for (var l = 0; l < availableNumbers.length; l++) {
forthDigit = availableNumbers[l];
possibleDigitValue = (firstDigit + secondDigit + thirdDigit + forthDigit);
possibleValues.push(possibleDigitValue);
}
availableNumbers.splice(k, 0, thirdDigit);
}
availableNumbers.splice(j, 0, secondDigit);
}
availableNumbers.splice(i, 0, firstDigit);
if (possibleValues.length >= numberOfPermutations) {
adding = false;
}
}
console.log(possibleValues);
return possibleValues;
}
}
arrayCreate([1,2,3,4,5,6,7,8,9],[0,0,0,0]);
var userNumberArray = ['0', '0', '0', '0']; //empty array of 0's as this value is not allowed, this array will store the computers auto-generated number
var availableNumbers = ['1', '2', '3', '4', '5', '6', '7', '8', '9'] //array of available numbers to be picked and added to the computerNumber array
//this function is used later to calculate the possible permutations of combinations of user guess
function factorial(x) {
if (x === 0) { return 1; }
else{
return x * factorial(x-1);
}
}
function arrayCreate(availableNumbers, userNumberArray) {
var possibleValues = []; //empty array to house all the possible combination of values that the user could enter i.e. 1234 to 9876
var numberOfPermutations = (factorial(availableNumbers.length) / factorial(availableNumbers.length - userNumberArray.length));
var adding = true;
var firstDigit, secondDigit, thirdDigit, forthDigit =0;
var possibleDigitValue = "";
while (adding === true) {
for (var i = 0; i < availableNumbers.length; i++) {
firstDigit = availableNumbers[i];
availableNumbers.splice(i, 1);
for (var j = 0; j < availableNumbers.length; j++) {
secondDigit = availableNumbers[j];
availableNumbers.splice(j, 1);
for (var k = 0; k < availableNumbers.length; k++) {
thirdDigit = availableNumbers[k]
availableNumbers.splice(k, 1);
for (var l = 0; l < availableNumbers.length; l++) {
forthDigit = availableNumbers[l];
possibleDigitValue = (firstDigit + secondDigit + thirdDigit + forthDigit);
possibleValues.push(possibleDigitValue);
}
availableNumbers.splice(k, 0, thirdDigit);
}
availableNumbers.splice(j, 0, secondDigit);
}
availableNumbers.splice(i, 0, firstDigit);
if (possibleValues.length >= numberOfPermutations) {
adding = false;
}
}
return possibleValues;
}
}
console.log(arrayCreate(availableNumbers, userNumberArray));
You could take a recursive approach by iterating the items and check if the item has been chosen before. If not then take that item and check the length of the part array.
If that has the wanted length, puth the part array to the result.
If not, iterate the given array and hand over the part array.
function arrayCreate(array, size) {
var result = [];
array.forEach(function iter(parts) {
return function (v) {
var temp = parts.concat(v);
if (parts.includes(v)) {
return;
}
if (temp.length === size) {
result.push(temp);
return;
}
array.forEach(iter(temp));
}
}([]));
return result;
}
console.log(arrayCreate([1, 2, 3, 4, 5, 6, 7, 8, 9], 4).map(a => a.join('')));
console.log(arrayCreate([1, 2, 3, 4, 5, 6, 7, 8, 9], 5).map(a => a.join('')));
console.log(arrayCreate([1, 2, 3, 4, 5, 6, 7, 8, 9], 6).map(a => a.join('')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
With separated function iter.
function arrayCreate(array, size) {
function iter(parts) {
return function (v) {
var temp = parts.concat(v);
if (parts.includes(v)) {
return;
}
if (temp.length === size) {
result.push(temp);
return;
}
array.forEach(iter(temp));
}
}
var result = [];
array.forEach(iter([]));
return result;
}
console.log(arrayCreate([1, 2, 3, 4, 5, 6, 7, 8, 9], 4).map(a => a.join('')));
console.log(arrayCreate([1, 2, 3, 4, 5, 6, 7, 8, 9], 5).map(a => a.join('')));
console.log(arrayCreate([1, 2, 3, 4, 5, 6, 7, 8, 9], 6).map(a => a.join('')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Solution for any size and any options
const makeUniqPermutations = (size, options) => {
if (size > options.length) {
throw new Error('Cannot make uniq permutations with that size and options');
}
if (size === 0) {
return [''];
}
const permutations = options.reduce((acc, option, index) => {
const restSize = size - 1;
const restOptions = [
...options.slice(0, index),
...options.slice(index + 1),
];
const restPermutations = makeUniqPermutations(restSize, restOptions);
const newPermutations = restPermutations.map(permutation => `${option}${permutation}`);
return [...acc, ...newPermutations];
}, [])
return permutations;
}
const options = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
const size = 4;
console.log(makeUniqPermutations(size, options));
Having a hard time googling for this since I'm not sure what the concepts are called, and all of the "combinations of two arrays/groups" SO posts are not giving me the output I would expect.
Example arrays:
var array1 = ['Bob', 'Tina'];
var array2 = [0, 100];
I can find possible combinations with nested looping through both arrays. But that would give me an output like:
var array1 = ['Bob', 'Tina'];
var array2 = [0, 100];
var options = []
array1.forEach(function (name) {
array2.forEach(function (number) {
options.push([name, number])
})
})
console.log(options);
> [ [ 'Bob', 0 ], [ 'Bob', 100 ], [ 'Tina', 0 ], [ 'Tina', 100 ] ]
this post (Creating Combinations in JavaScript) gives me the output above
But what I'm really looking for would give me arrangements/combinations like this:
[
[['Bob', 0], ['Tina', 0]],
[['Bob', 0], ['Tina', 100]],
[['Bob', 100], ['Tina', 0]],
[['Bob', 100], ['Tina', 100]]
]
And it would need to be able to scale with longer arrays, but 2x2 is the easiest example.
This cartesian example here (Matrix combinations of two arrays in javascript) also gave me broken out strings and not correlated arrangements:
[ { '0': 'B', '1': 'o', '2': 'b' },
{ '0': 'B', '1': 'o', '2': 'b' },
{ '0': 'T', '1': 'i', '2': 'n', '3': 'a' },
{ '0': 'T', '1': 'i', '2': 'n', '3': 'a' } ]
I have been looking through google and SO but I'm hitting roadblocks because I'm not sure what I'm actually looking for.
I hope this might help you to get your actual combination:
var array1 = ['Bob', 'Tina'];
var array2 = [0, 100];
var resultArray = []
for (var i = 0; i < array1.length; i++) {
for (var j = 0; j < array2.length; j++) {
var tempArray = [];
tempArray.push(array1[i]);
tempArray.push(array2[j]);
resultArray.push(tempArray);
}
}
for (var i = 0; i < array2.length; i++) {
for (var j = 0; j < array1.length; j++) {
var tempArray = [];
tempArray.push(array1[j]);
tempArray.push(array2[i]);
resultArray.push(tempArray);
}
}
console.log(resultArray);
I'll give you some hints that you might find helpful. First, I assume you know how to iterate over an array:
var array1 = ['Bob', 'Tina'];
for (var i = 0; i < array1.length; i++) {
// you can access the ith element using array1[i]
// for example:
alert(array1[i]);
}
I also assume you know how to execute nested looping:
var array1 = ['Bob', 'Tina'];
var array2 = [0, 100];
for (var i = 0; i < array1.length; i++) {
for (var j = 0; j < array2.length; j++) {
alert(array1[i] + " " + array2[j]):
}
}
What you may be missing is how to construct a new array:
var five = 5;
var six = 6;
var myArray = [five, six];
You also may be missing the ability to push a new array onto an existing "master" array:
var five = 5;
var six = 6;
var masterArray = [];
for (var i = 0; i < 10; i++) {
masterArray.push([five, six]);
}
Hope this helps, and good luck!
This solves the problem, but don't know how efficient it is - I'll bet there's much better ways of doing it.
var array1 = ['Bob', 'Tina', 'Sam'];
var array2 = [0, 100, 200];
var resultCount = Math.pow(array2.length, array1.length);
var results = new Array(resultCount);
for(var i = 0; i < resultCount; i++) {
results[i] = new Array(array1.length);
}
for(var row = 0; row < resultCount; row++) {
for(var column = 0; column < array1.length; column++) {
var result = row * array1.length + column;
var category = array1.length * Math.pow( array2.length, array1.length - 1 - column);
var idx = ~~(result / category) % array2.length;
results[row][column] = [ array1[column], array2[idx] ];
}
}
console.log(results);
I think you could actually do this in terms of number/string manipulation by thinking of array2 as a radix (each value maps to a digit) and array1 as the number of digits. As long as array2 has 36 or less elements you could convert every number from 0 up to the number of combinations as a string (Number.toString(radix)) and then convert each char from the resulting string back to an index into your arrays.
I have N number of arrays in an array, for now N = 3
[[1,2,3, "a","b"] , [3,4,5,"c"], [6,7,8]...]
I would like for it to return
[[1,3,6], [2,4,7], [3,5,8], ...., ["a","c", ""], ["b", "",""]]
There are lot of solutions of combining two arrays but I want to handle any number of arrays. I would like for it to return above. I am looking to do this without underscore or jquery.
Values=[];
status = [[1,2,3, "a","b"] , [3,4,5,"c"], [6,7,8]];
status_name = status[0]; //take the longest one always
for (i = 0; i < status_name.length; ++i)
{
Values[i] =Array(status_name[i], status[i+1][i]);
}
why not nest loops ?
sth. like this warning pseudocode
Values=[];
status = [[1,2,3, "a","b"] , [3,4,5,"c"], [6,7,8];
status_name = status[0];
for (i = 0; i < status.length; ++i)
{
for (k = 0; k < status[i].length; ++i)
{
Values[i] =Array(status[i][k], status[k+1][k]);
}
}
var originalArray = [[1, 2, 3, "a", "b"], [3, 4, 5, "c"], [6, 7, 8]];
var theValues = new Array();
var actualArray = originalArray.pop();
var maxLength = originalArray.length;
while (actualArray) {
for (var i = 0; i < actualArray.length; i++){
var newArray = theValues[i];
if (!newArray) {
theValues[i] = new Array();
}
theValues[i].push(actualArray[i])
}
actualArray = originalArray.pop();
}
for (var i = 0; i < theValues.length; i++) {
for (var j = maxLength - theValues[i].length; j >= 0; j--) {
theValues[i].push("");
}
}
Conceptually, this is most easily achieved using nested loops;
var a = [[1, 2, 'x'], ['a', 'b'], ['+', '-', 'y', 'z']]; // input array
function transform(a) {
var i, j, // two loops = two variables to iterate with
foundSomething, // a flag so we know to stop
b = []; // output array
i = 0;
do { // loop for i
foundSomething = false;
b[i] = [];
for (j = 0; j < a.length; ++j) { // loop for j
if (i in a[j]) { // something exists at this level of i
foundSomething = true;
b[i].push(a[j][i]);
} else { // nothing here
b[i].push(''); // insert empty string
}
}
++i;
} while (foundSomething);
b.length = b.length - 1; // snip empty end
return b;
}
transform(a); // [[1, "a", "+"], [2, "b", "-"], ["x", "", "y"], ["", "", "z"]]
Sorting required?
a.sort(function (a, b) {return a.length < b.length;}); // bigger arrays first
transform(a); // [["+", 1, "a"], ["-", 2, "b"], ["y", "x", ""], ["z", "", ""]]
If you're always doing this sort, you can further optimise transform i.e. because you know that a[x].length >= a[y].length for all x < y, you don't need to flag whether you found something