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
Related
In this function I count the number of consecutive zeros that should be at least of length zerosMin. Is there any way I could return the first index of the start of the sequences? For example, for arr = [1,0,0,0,0,0,1,0,0,0,0] it would be [1,7]
function SmallestBlockOfZeros(arr, zerosMin) {
let result = [];
let counter = 1;
for (let i = 0; i < arr.length; i++) {
if (arr[i] == 0) {
if (arr[i] === arr[i + 1]) {
counter++;
} else if (counter >= zerosMin) {
result.push(counter);
counter = 1;
} else {
counter = 1;
}
}
}
return result;
}
let arr = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0];
let zerosMin = 4;
console.log(SmallestBlockOfZeros(arr, zerosMin));
//Console output : [5,4]
You can iterate through the array, pushing an index into the result array whenever you encounter a block of 0 values that is at least zerosMin long, and then skipping all those 0 values until you find the next non-0 value or pass the point at which a zerosMin string of 0s could occur:
let arr = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0];
let zerosMin = 4;
let zeroStarts = [];
for (let i = 0; i <= arr.length - zerosMin; i++) {
if (arr.slice(i, i + zerosMin).filter(Boolean).length == 0) {
zeroStarts.push(i);
i += zerosMin;
while (i <= arr.length - zerosMin && arr[i] == 0) {
i++;
}
}
}
console.log(zeroStarts);
Note I've used filter(Boolean) because 0 is falsey; if you were searching for a run of non-zero values you would use something like filter(v => v != 0)
If you don't need to actually iterate elements, you can use a shortcut
function foo(arr, min)
{
let el = arr.join("").match(new RegExp('0{' + min + ',}'));
return [el.index, el.index + el[0].length];
}
console.log(foo([1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], 3));
For start of each chain of zeros:
function indexOfValue(arr, val) {
var indexes = [], i;
for(i = 0; i < arr.length; i++)
if (arr[i] === val)
indexes.push(i);
return indexes;
}
(see How to find index of all occurrences of element in array?)
The code you posted above appears to work for length of blocks of 0s.
While iterating the items, keep track of last non-zero index and push the index to output array when criteria matches.
const SmallestBlockOfZeros = (arr, zerosMin) => {
let index = 0;
const output = [];
for (let i = 0; i <= arr.length; i++) {
if (arr[i] !== 0 || !(i in arr)) {
i - index - 1 >= zerosMin && output.push(index + 1);
index = i;
}
}
return output;
};
const arr = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0];
const zerosMin = 4;
console.log(SmallestBlockOfZeros(arr, zerosMin));
Hey guys in short i have this 4x4 Matrix input
Matrix = [
["X", "X", null, null],
[null, "X", "X", "X"],
[null, null, "X", "X"],
["X", "X", null, null],
];
we wanna have as an output a new Matrix for instance for rows, wherever you find an "X" put 1 then in each "X" increment by one otherwise null replace it with 0 and continue from 0 we should have an output like that
output Matrix : [
[1, 2, 0, 0],
[0, 1, 2, 3],
[0, 0, 1, 2],
[1, 2, 0, 0],
];
we should do 4 outputs (Matrix)s one for rows, one for columns and one for first then one for second diagonal
Output diagonal should be :
left to bottom right diagonal means \ output = [
[1, 1, 0, 0],
[0, 2, 2, 1],
[0, 0, 3, 3],
[1, 1, 0, 0],
];
right to bottom left diagonal means / output = [
[1, 1, 0, 0],
[0, 1, 1, 1],
[0, 0, 2, 1],
[1, 3, 0, 0],
];
no matter how much excecution time but should be readable generic and easy snippets as possible avoiding complexity i did the rows and stuck on diagonals with for loops if possible here my code:
const Rows = (matrix) => {
let inc = 0;
return matrix.map((array) =>
array.map((_, ind, list) => {
if (list[ind] == player) {
inc += 1;
return (list[ind] = inc);
} else {
inc = 0;
return (list[ind] = 0);
}
})
);
};
I'll give the code for top-left to bottom-right diagonal. You can do the similar for top-right to bottom-left diagonal.
let Matrix = [
["X", "X", null, null],
[null, "X", "X", "X"],
[null, null, "X", "X"],
["X", "X", null, null],
];
let rows = 4,
cols = 4;
// this is making an array of 4 arrays inside of it filled with null
let OutputMatrix = [...new Array(rows).keys()].map((x) => [...new Array(rows).keys()].map((i) => (i = i + x * rows)));
//i goes from last row to first row.
let counter = 1,
i = rows - 1,
j = 0,
k = 1;
while (i >= 0) {
while (i < rows && j < rows) {
if (Matrix[i][j] != "X") {
counter = 0;
}
OutputMatrix[i][j] = counter++;
i++, j++;
}
j = 0;
++k;
i = rows - k;
}
//j goes from second column to last column
(i = 0), (j = 1), (k = 1), (counter = 1);
while (j < cols) {
while (i < rows && j < cols) {
if (Matrix[i][j] != "X") {
counter = 0;
}
OutputMatrix[i][j] = counter++;
i++, j++;
}
i = 0;
k++;
j = k;
}
console.log(OutputMatrix);
Matrix.forEach(row => {
var c = 0
var rowIndex = Matrix.indexOf(row)
row.forEach(value => {
var valueIndex = row.indexOf(value)
if (value === null) {
c = 0
}
else{
c++;
}
Matrix[rowIndex][valueIndex] = c
});
});
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; }
Having Data in array of arrays with duplicate arrays of Oth position.
explanation
Compare arrays with its zero th position and make the result accurately.
let array = [["2018-03-09", 10, 11, 0],["2018-03-10", 100, 101, 105],["2018-03-15", 20, 0, 25],["2018-03-09", 0, 0, 15],["2018-03-15", 0, 10, 0]]
let output = [];
for (let i = 0; i < array.length; i++) {
let key = array[i][0]
let index = output.findIndex(x => x[0] == key)
if (index >= 0) {
for (let k = 1; k < array[i].length; k++) {
if (array[i][k] >= output[index][i]) {
output[index][k] = array[i][k]
} else {
output[index][k] = output[index][i]
}
}
} else {
output.push(array[i])
}
}
console.log(output)
Required Output
output=[["2018-03-09",10,11,15],["2018-03-10",100,101,105],["2018-03-15",20,10,25]]
How can I achieve this?
You could use a lookup object to find previous entries with the same values, then merge them. Array destructuring is helpful to make the code clean:
const byDate = {};
const result = [];
for(const [date, ...values] of array) {
if(byDate[date]) {
values.forEach((v, i) => byDate[date][i + 1] = Math.max(byDate[date][i + 1], v));
} else {
result.push(byDate[date] = [date, ...values]);
}
}
For better readability, you can update the array in a separate function (I kept the for loop method you used, although we could use here a forEach() call).
Here, updateEntry will look in an output array (entries argument) for an existing entry, updating it if found otherwise it will append it to the output array.
Below a working snippet.
function updateEntry(entries, entry) {
for (let i = 0; i < entries.length; i++) {
if (entry[0] != entries[i][0]) continue;
for (let j = 1; j < entry.length; j++) {
if (entry[j] >= entries[i][j])
entries[i][j] = entry[j];
}
return;
}
entries.push(entry);
}
let array = [
["2018-03-09", 10, 11, 0],
["2018-03-10", 100, 101, 105],
["2018-03-15", 20, 0, 25],
["2018-03-09", 0, 0, 15],
["2018-03-15", 0, 10, 0]
];
let output = [];
for (let i = 0; i < array.length; i++) {
updateEntry(output, array[i]);
}
console.log(output);
Use array.reduce to build an object with the identifier (the date) as the keys, which sums the other three values. Then, use Object.values to return your desired array output.
let array = [["2018-03-09", 10, 11, 0],["2018-03-10", 100, 101, 105],["2018-03-15", 20, 0, 25],["2018-03-09", 0, 0, 15],["2018-03-15", 0, 10, 0]];
let output = Object.values(array.reduce((r, e) => {
var k = e[0];
if (!r[k]) r[k] = [k, 0, 0, 0];
r[k][1] += e[1];
r[k][2] += e[2];
r[k][3] += e[3];
return r;
}, {}));
console.log(output);
I am looking to create a pyramid array from number values. The requirement is that I am to work from an array that which in my case has 3 rows with 5 columns. I need to create a pyramid that looks like the example below.
Here is what I want to achieve exactly..
[0, 0, 1, 0, 0]
[0, 1, 1, 1, 0]
[1, 1, 1, 1, 1]
So far my code looks something like this..
var a = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]];
function array_pyramid( array ){
for (i = 0; i < array.length; i++){
for (j = 0; j <= Math.floor(array[i].length / 2); j++){
var tmp = array[i].length / 2;
console.log (Math.floor(tmp));
if ( i < j ) {
array[i][j] = 1;
}
}
}
return array;
}
function print_array(array) {
for (var i = 0; i < array.length; i++) {
console.log(array[i]);
}
}
//console.log(a);
//print_array(a);
print_array(array_pyramid(a));
Try example below. I purposely kept variable names long and descriptive and kept operations in multiple steps rather than inline for the ease of analyzing.
var a = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]];
function array_pyramid(array){
var pBlocksCount = 1;
var currentRow, rowIndex, columnIndex, columnsCount, rowsCount = array.length;
for(rowIndex=0; rowIndex<rowsCount; rowIndex++){
currentRow = array[rowIndex];
columnsCount = currentRow.length;
var piramidDrawIndex = parseInt(columnsCount/2);
var piramidDrawOffset = parseInt(pBlocksCount/2);
var piramidDrawTrigger = piramidDrawIndex-piramidDrawOffset;
var blocksToDraw = pBlocksCount;
for(columnIndex=0; columnIndex<columnsCount; columnIndex++){
if(columnIndex>=piramidDrawTrigger){
if(blocksToDraw){
currentRow[columnIndex]=1;
blocksToDraw--;
}
}
}
pBlocksCount+=2;
}
return array;
}
function print_array(array) {
for (var i = 0; i < array.length; i++) {
console.log(array[i]);
}
}
print_array(array_pyramid(a));
This will probably fail for most other cases you could come up with, but works in this specific instance:
function array_pyramid( array ){
var mid = Math.floor(array[0].length/2);
for(var i=0;i<array.length;i++){
for(var j=0;j<array[i].length;j++){
var boundsLower = mid-i;
var boundsUpper = mid+i;
if(j>=boundsLower && j<=boundsUpper){
array[i][j] = 1;
}
}
}
return array;
}
Live example: https://jsfiddle.net/o6t1cbdu/
Try this ...
function array_pyramid(array){
var limit = [0,0];
for (var i = array.length - 1, limit = [0, (array[0] || []).length - 1]; i >= 0; i--) {
for (var j = limit[0]; j <= limit[1]; j++) {
array[i][j] = 1;
}
limit[0]++; limit[1]--;
}
return array;
}
I hope it helps
You were starting down the right track with an inner and an outer loop, as well as your use of division to try to account for the midpoint.
Here is a verbose and heavily commented modification of your code that accounts for any number of columns (odd or even) and uses a range that widens during row progression to determine which columns should be 1 or 0. I've included a second array, b, to show it works for even column counts as well.
var a = [
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]
],
b = [
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0]
];
function array_pyramid (a) {
// Use first row to determine row length, assume all others are the same
var base_length = a[0].length,
// Get a modulus to account for odd or even row length
mod = base_length % 2,
// Find the middle point
mid_point = Math.floor(base_length / 2) + mod,
// Account for zero-index of arrays
zero_indexed = mid_point - 1,
// Produce an initial set of boundaries
marker_range = {
lower: zero_indexed,
upper: (mod === 1) ? zero_indexed : (zero_indexed + 1)
};
// Iterate the array's rows
a.forEach(function (row) {
// Iterate the row's cols
row.forEach(function (col, i) {
// Compare index to boundaries to determine if we're outputting a 1 or a 0
row[i] = (i >= marker_range.lower && i <= marker_range.upper) ? 1 : 0;
});
// If we still have room to expand, widen the range in each direction
if (marker_range.lower > 0) {
marker_range.lower -= 1;
marker_range.upper += 1;
}
});
return a;
}
function print_array(a) {
var i;
console.log('-- Start output');
for (i = 0; i < a.length; i++) {
console.log(' ', a[i]);
}
console.log('-- End output');
console.log(' ');
}
console.log('a (odd col count):');
print_array(array_pyramid(a));
console.log('b: (even col count)');
print_array(array_pyramid(b));
So here is my code, it works fine.
The idea is that you find the main vertical center of the matrix and the sideA and sideB variables represent the left and the right side of the pyramid. Once you've found the sides, you make them equal to one as well as everything between them ( if (j <= sideA && j >= sideB) ). I hope that helps. :)
function array_pyramid ( array ) {
var item, sideA, sideB;
if (array instanceof Array) {
for (var i = 0; i < array.length; i++) {
item = array[i];
centerIndex = Math.floor(item.length / 2);
sideA = centerIndex + i;
sideB = centerIndex - i;
for (var j = 0; j < item.length; j++) {
if (j <= sideA && j >= sideB) {
item[j] = 1;
}
}
}
return array;
} else {
return 'Invalid array';
}
}
array_pyramid ([
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
]);
When you run that code in the console it will return this:
[0, 0, 1, 0, 0]
[0, 1, 1, 1, 0]
[1, 1, 1, 1, 1]
And that's it.