Related
I'm struggling with the logic to do the Recursion.
For the grid below I need to search a word and return an array of indexes that form the word if it exists or an empty array [] if it doesn't exist.
The word may start anywhere in the grid, and consecutive letters can be either immediately below or immediately to the right of the previous letter.
grid = [
['c', 'c', 'x', 't', 'i', 'b'],
['c', 'c', 'a', 't', 'n', 'i'],
['a', 'c', 'n', 'n', 't', 't'],
['t', 'c', 's', 'i', 'p', 't'],
['a', 'o', 'o', 'o', 'a', 'a'],
['o', 'a', 'a', 'a', 'o', 'o'],
['k', 'a', 'i', 'c', 'k', 'i'],
];
word = "catnip"
find_word_location(grid, word)
// OUTPUT [ (1, 1), (1, 2), (1, 3), (2, 3), (3, 3), (3, 4) ]
This is what I have so far but it's not working.
function find_word_location (grid, word) {
const dfs = (i, j, wordIndex, res) => {
if (wordIndex == word.length) return;
if (
i > grid.length - 1 ||
j > grid[0].length - 1 ||
grid[i][j] !== word[wordIndex]
)
return;
if (grid[i][j] == word[wordIndex]) {
res.push(`(${i},${j})`);
grid[i][j] = "#";
}
dfs(i + 1, j, wordIndex + 1, res);
dfs(i, j + 1, wordIndex + 1, res);
grid[i][j] = word[wordIndex];
return res;
};
for (let i = 0; i < grid.length; i++) {
for (let j = 0; j < grid[0].length; j++) {
if (grid[i][j] == word[0]) {
let result = dfs(i, j, 0, []);
return result;
}
}
}
return [];
}
Some of the issues:
After the initial call of dfs your code always returns the result. This means that it assumes that if the first letter matches, the whole word must be matched starting at that cell. But this is not true. It might not find a match there, while there might be other places in the grid with that first letter which do give a full word match. So this return statement should be conditional (only when there is success).
The array referenced by res only grows. It never shrinks. Realise there is only one res array -- referenced by all res variables that live in the dfs execution contexts. So all partial matches (that eventually fail to lead to a full match) are collected in it, and concatenated one after the other. There is no backtracking applied to it.
I find it more elegant to actually only start building an array when the whole word has been matched, and then fill up an array while getting out of the recursive calls (as opposed to doing this while deepening the recursion).
The recursive calls of dfs completely ignore the values that those calls return, so no distinction is made between failure and success. You'd need to check the result of the first recursive call and if it was successful, the second one should not even be made.
Not a problem, but the condition in if (grid[i][j] == word[wordIndex]) { will always be true, given you already tested the opposite condition in the preceding if statement.
Here is a correction to your code, also implementing the idea I expressed in the second point, i.e. only filling up an array when it is already known there was a success:
// No res argument. res will be populated "inside-out" via the return value
function find_word_location (grid, word) {
const dfs = (i, j, wordIndex) => {
if (wordIndex == word.length) return []; // Start a solution with this res
if (
i > grid.length - 1 ||
j > grid[0].length - 1 ||
grid[i][j] !== word[wordIndex]
)
return;
grid[i][j] = "#";
// Use the returned value
// and apply short-circuit to avoid useless second call
const res = dfs(i + 1, j, wordIndex + 1) || dfs(i, j + 1, wordIndex + 1);
grid[i][j] = word[wordIndex];
if (res) res.unshift([i, j]); // Extend the path we got from recursion
return res;
};
for (let i = 0; i < grid.length; i++) {
for (let j = 0; j < grid[0].length; j++) {
if (grid[i][j] == word[0]) {
let result = dfs(i, j, 0, []);
if (result) return result; // conditionally
}
}
}
return [];
}
var grid = [
['c', 'c', 'x', 't', 'i', 'b'],
['c', 'c', 'a', 't', 'n', 'i'],
['a', 'c', 'n', 'n', 't', 't'],
['t', 'c', 's', 'i', 'p', 't'],
['a', 'o', 'o', 'o', 'a', 'a'],
['o', 'a', 'a', 'a', 'o', 'o'],
['k', 'a', 'i', 'c', 'k', 'i'],
];
var word = "catnip";
var result = find_word_location(grid, word);
console.log(result);
This approach does not hand over the result to the recursive call.
The function takes grid, the word or the left over word part, and the actual indices, which has zero as default value.
Inside, the exit condition comes first by checking boundaries.
Then a check for the wanted character follows.
Inside it check with new word length, without actual character and if an empty string, it returns the indices.
The rest is nearly identically without the part for checking the found indices and if they are adjacent to the actual elememnt.
Roughly, get sub indices, check if there are indices and return the result either with actual indices (letter match) or just the rest.
const
findWord = (grid, word, i = 0, j = 0) => {
const isAdjacent = (x, y) => x === i && y === j + 1 || x === i + 1 && y === j;
let sub;
if (i + 1 === grid.length || j + 1 === grid[i].length) return [];
if (grid[i][j] === word[0]) {
const w = word.slice(1);
if (!w.length) return [[i, j]];
sub = findWord(grid, w, i + 1, j);
if (sub.length && isAdjacent(...sub[0])) return [[i, j], ...sub];
sub = findWord(grid, w, i, j + 1);
if (sub.length && isAdjacent(...sub[0])) return [[i, j], ...sub];
}
sub = findWord(grid, word, i + 1, j);
if (sub.length) return sub;
sub = findWord(grid, word, i, j + 1);
if (sub.length) return sub;
return [];
},
grid = [['c', 'c', 'x', 't', 'i', 'b'], ['c', 'c', 'a', 't', 'n', 'i'], ['a', 'c', 'n', 'n', 't', 't'], ['t', 'c', 's', 'i', 'p', 't'], ['a', 'o', 'o', 'o', 'a', 'a'], ['o', 'a', 'a', 'a', 'o', 'o'], ['k', 'a', 'i', 'c', 'k', 'i']],
word = "catnip",
result = findWord(grid, word);
console.log(result.map(p => p.join('-')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have an array: var array = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
I want the array to be a length of 3, but I don't want to remove the consecutive elements. I want to remove elements evenly from an array.
Since array.length is 9, I want to remove 6 elements from it and I always want to keep the first element. so in this case, var array would be like ['a', 'e', 'i']
I was doing like this so far:
var extraLength = array.length - 3;
var eachVal = Math.round(array.length/extraLength);
for (var j = 0; j < extraLength; j++){
for(var i = array.length -1; i >= 0; i-- ) {
if (i == eachVal*j && i != 0) {
array.splice(i, 1)
}
}
}
This gives an error saying array.splice is not a function.
Also, as I write this, I realized that this only works when array.length/extraLength is an even number, so in the example above, it does not work.
How can I achieve this?
This gives an error saying array.splice is not a function.
There is no error, at least with the code you presented in the question. See the snippet below for the result of your code:
var array = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'];
var extraLength = array.length - 3;
var eachVal = Math.round(array.length/extraLength);
for (var j = 0; j < extraLength; j++){
for(var i = array.length -1; i >= 0; i-- ) {
if (i == eachVal*j && i != 0) {
array.splice(i, 1)
}
}
}
console.log(array);
I want the array to be a length of 3, but I don't want to remove the
consecutive elements. I want to remove elements evenly from an array.
Since array.length is 9, I want to remove 6 elements from it and I
always want to keep the first element. so in this case, var array
would be like ['a', 'e', 'i']
But, this only one use-case. How do you want to handle odd/even sized arrays? I assume, your basic requirement is to remove elements with some delta based on the length of the array and the desired resulting size. And you would be fine by truncating the trailing elements.
To do that would be easy by dividing the length of the array by your desired size and flooring it to avoid fractions. Adding one to that will allow you to have a delta step factor which is suitable for odd sized arrays.
Once done that, you just iterate the array with a step size of your calculated delta factor.
Example:
var array = [
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'],
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'],
['a', 'b', 'c', 'd', 'e']
],
factor, result, desiredSize = 3;
for (i=0; i < array.length; i++) {
// calculate the delta factor
factor = Math.floor(array[i].length / desiredSize) + 1;
factor = (desiredSize % 2 === 0) ? --factor : factor;
result = [];
// iterate with the step size of the calculated facor
for (j = 0; j < array[i].length; j = j + factor) {
result.push(array[i][j]);
}
console.log(result);
}
In the above example, I am using a nested array to show multiple arrays of differing lengths to keep the code size compact. Check the console to see the result for each of the arrays.
Edit:
Changed the code to take into account if the desiredSize is an even number. Have to just rollback the increment on the floored delta factor. This will make it more evenly distributed. Thank you #Andrey Popov for the comment.
I have four arrays like this
var Broker = ['A', 'B', 'C'];
var Currency = ['C', 'D', 'E'];
var Time = ['F', 'G', 'H', 'I'];
var Mode = ['J', 'K', 'L'];
so all theses arrays are shown in multiple select separtely.so when user selects the multiple field from each multi select dropdown i like to list all the paring possiblities with selected items
exampleif user choose A and B from Broker, C from currency, F,G from time and J from mode the paring possiblity should be stored in another separate array like this
var paired = [{borker:A,currency:C,time:F, mode: J},{borker:A,currency:C,time:G, mode: J},{borker:A,currency:C,time:F, mode: J}, {borker:B,currency:C,time:F, mode: J},{borker:B,currency:C,time:G, mode: K},{borker:B,currency:C,time:F, mode: L}];
I may missed the items in paried array but i need atleast one unique item from all the selected arrays.Its kind of set.So can you guys how can i obtain this kind of result.
This code creates an array called permutations which holds an object for every possible permutation of choices. The nested for-loops are the trick to permutations.
var Broker = ['A', 'B', 'C'];
var Currency = ['C', 'D', 'E'];
var Time = ['F', 'G', 'H', 'I'];
var Mode = ['J', 'K', 'L'];
var permutations = [];
for(var i = 0; i < Broker.length; i++) {
for(var j = 0; j < Currency.length; j++) {
for(var k = 0; k < Time.length; k++) {
for(var l = 0; l < Mode.length; l++) {
permutations.push({
borker:Broker[i],
currency:Currency[j],
time:Time[k],
mode:Mode[l]
});
}
}
}
}
I am trying to translate all alphabets in a message to p alphabet(s) in the sequence. for example: Translate("bbcd", 2) will return "ddef". I am stuck at the array part where alphabets[j+p] returns undefined. If I do alphabets[j-p], it will work.
Here is my code:
function Translate(Message, p) {
var alphabets = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
var message_array = Message.split('');
for(var i in message_array){
for(var j in alphabets){
if(message_array[i]==alphabets[j]){
message_array[i]=alphabets[j+p];//returns undefined
}
}
}
return message_array;
}
console.log(Translate("bbcd", 2));
The problem is j+p which is doing a string concatenation, typeof j will return string as you are reading the array index using for...in
function Translate(message, p) {
var alphabets = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
return message.split('').map(function(c) {
var idx = alphabets.indexOf(c);
return idx == -1 ? c : alphabets[(idx + p) % alphabets.length]
});
}
var value = Translate("azpq", 2);
result.innerHTML = JSON.stringify(value);
<div id="result"></div>
alphabets[j+p]; returns undefined for j == 26 that it will reach for the inner loop iteration.
use indexOf method of array and change your loop structure to
for(var i in message_array)
{
var index = alphabets.indexOf( message_array[ i ] );
message_array[ i ] = alphabets[ index + 2 ];
}
This also will reach 'undefined' if your Message has a y or z in it.
so, you might want to cycle it back to the beginning
for(var i in message_array)
{
var index = alphabets.indexOf( message_array[ i ] );
message_array[ i ] = alphabets[ (index + 2) % alphabets.length ];
}
function Translate(Message, p) {
var alphabets = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
var messageLength = Message.length;
var returnMessage = '';
for(var i=0; i< messageLength; i++) {
var myChar = Message.charAt(i);
var placeChar = alphabets.indexOf(myChar);
myChar = alphabets[placeChar + p];
returnMessage += myChar;
}
return returnMessage;
}
console.log(Translate("bbcd", 2));
You need to break once the value is found. Otherwise the inner loop will find a match again on the coming cycles.
function Translate(Message, p) {
var alphabets = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
var message_array = Message.split('');
for (var i in message_array) {
for (var j in alphabets) {
if (message_array[i] == alphabets[j]) {
console.log(alphabets[parseInt(j) + parseInt(p)])
message_array[i] = alphabets[parseInt(j) + parseInt(p)]; //returns undefined
break;
}
}
}
return message_array;
}
alert(Translate("bbcd", 2));
You need to make sure that j+p is never bigger than the length of alphabets. This will result in a "out of bounds" error. e.g. p = 30.
A fix is to just check the length compared to p and returns something that is defined.
message_array[i] = (j+p > alphabets.length) ? alphabets[j+p] : alphabets[j]; // returns element at j if out of bounds
This suggestion works with an alphabet string instead of an array.
You can access a string like an array for a single character. For the lookup i suggest to use indexOf(), a method availabele at string objects String#indexOf() as well as array objects Array#indexOf(). Both methods returns the position of the found item/string/character or -1 if not found.
For the result I took an empty string and concatinated it with the new character.
For the correct range of the index, while adding some value, the method of choice is to use the modulo operator. It returns the reminder of a division by the second number. Here it is the length of the alphabet string.
function translate(message, p) {
var alphabet = 'abcdefghijklmnopqrstuvwxyz',
i, pos, result = '';
for (i = 0; i < message.length; i++) {
pos = alphabet.indexOf(message[i]);
result += alphabet[(pos + p) % alphabet.length];
}
return result;
}
document.write(translate("bbcd", 2));
In Javascript, I have 2 arrays of 15 string elements, each of 0 to 17 characters.
How can I tell if one of the values of the first of these two arrays has a value equal to one of the values of the second array?
Example:
var array1 = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o'];
var array2 = ['z','z','z','z','z','z','z','z','z','z','z','z','z','o','z'];
myFunction(array1,array2); // returns false
Example 2:
var array1 = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','s'];
var array2 = ['z','z','z','z','z','z','z','z','z','z','z','z','z','o','z'];
myFunction(array1,array2); // returns true
Eric J.'s suggestion of an intersection is probably most elegant way to approach the problem.
A straightforward translation of what you're asking could work like this:
function containsAny(array1, array2) {
for (var i=0; i<array1.length; i++) {
for (var j=0; j<array2.length; j++) {
if (array1[i] == array2[j]) return true;
}
}
return false;
}
var array1 = ['a','b','c'];
var array2 = ['1','2','3'];
var array3 = ['a','b','2'];
containsAny(array1, array2); // returns false
containsAny(array2, array3); // returns true
containsAny(array1, array3); // returns true
Assuming dbaupp is right and you have a typo, you want to find the intersection of the two arrays and see if it is non-empty.
The intersection of two sets means the set of elements that both original sets have in common. If there is at least one element in common, the intersection will be non-empty.
To do that, see
Simplest code for array intersection in javascript
This code checks if the two lists have a common element, which is done by sorting the lists and then stepping through them together, advancing whichever list is "behind".
function(list1, list2) {
var l1 = list1.sort(), l2 = list2.sort(),
len1 = l1.length, len2 = l2.length,
i1 = 0, i2 = 0;
while (i1 < len1 && i2 < len2) {
if (l1[i1] == l2[i2])
return true;
if (l1[i1] < l2[i2])
i1++;
else
i2++;
}
return false;
}
NB. as Eric said you could also just intersect the two lists, and check that the resulting list is non-empty, but this code here will be more efficient since it doesn't have to generate a whole new list, nor does it have to go through all of both lists if there is a common element.
Ok, assuming I'm understanding your problem correctly, I tossed together a Fiddle that will match the elements of 2 arrays using the JQuery 'each' method:
http://jsfiddle.net/phillipkregg/Ug3DM/1/
var array1 = ["a","b","c","o"];
var array2 = ["z","z","b","z","z","o"];
array1.each(function(item){
var element = item;
var match = [];
array2.each(function(item2) {
if (item2 === element)
{
match.push(item2);
alert(match);
}
});
});
Maybe that will get you started.
I try to use the 'each' method upstairs, but it seems not work, while 'each' is used for objects, not for array.
so I change the code.
var array1 = ["a","b","c","o"];
var array2 = ["z","z","b","z","z","o"];
var match = [];
$.each(array1, function(key, val){
var element = val;
$.each(array2, function(key, val){
if(element === val)
{
match.push(val);
}
});
});
$.each(match, function(key, val){
alert(key+'--'+val);
});
Most browsers use builtin indexOf and filter methods of Arrays,
if you use these methods often you can conditionally add
them to older browsers.
var array1= ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 's'];
var array2= ['z', 'z', 'z', 'z', 'z', 'z', 'z', 'z', 'z', 'z', 'z', 'z', 'z', 'o', 'z'];
var array3= ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'o', 'k', 'l', 'm', 'n', 's'];
1. array1.inCommon(array2)>>
(array length 0)
2. array2.inCommon(array3)>>
(array length 1)
o
3. array3.inCommon(array1)>>
(array length 14)
a, b, c, d, e, f, g, h, i, k, l, m, n, s
Array.prototype.inCommon= function(ar){
return this.filter(function(itm){
return ar.indexOf(itm)!= -1;
});
}
Array.prototype.indexOf= Array.prototype.indexOf || function(what, i){
if(typeof i!= 'number') i= 0;
var L= this.length;
while(i< L){
if(this[i]=== what) return i;
++i;
}
return -1;
}
Array.prototype.filter= Array.prototype.filter || function(fun, scope){
var T= this, A= [], i= 0, itm, L= T.length;
if(typeof fun== 'function'){
while(i< L){
if(i in T){
itm= T[i];
if(fun.call(scope, itm, i, T)) A[A.length]= itm;
}
++i;
}
}
return A;
}