I'm trying to understand the following recursive function below to teach myself recursion. My attempt to explain it is below the expected output and the function itself. what am I missing? I'm not seeing the process where you get from 'abc' to 'acb'. my attempt to understand it got me from 'abc' right to 'bac'.
example usage:
var anagrams = allAnagrams('abc');
console.log(anagrams); // [ 'abc', 'acb', 'bac', 'bca', 'cab', 'cba' ]
var allAnagrams = function(string) {
var uniqueOutput = {};
(function anagram(ana, str) {
// could have also written this as: if(!str)....
if (str === '') {
uniqueOutput[ana] = 1;
}
//recursive call for the length of the anagram.
for (var i = 0; i < str.length; i++) {
anagram(ana + str[i], str.slice(0, i) + str.slice(i + 1));
console.log(ana);
}
})('', string);
console.log(uniqueOutput)
return Object.keys(uniqueOutput);
};
// you are calling the recursive function like this: anagram([anagram=]'', [string=]'abc')
// so the base case is not met on the first iteration since the string isn't empty
// first iteration: i = 0
// anagram('' + 'a' + 'bc' [from str.slice(0 +1)]) ---> resolves to "abc") ---> anagram("abc")
//second iteration: i = 1. we are still in the original call from line 37.
// here below, does "ana" stay as '' since we are still inside the initial recursion call?
//anagram('' + b + a + c) ---- resolves to "bac" ---> anagram("bac")
//third and last iteration iteration: i = 2
//anagram(" " + c + c) ----> anagram("cc") ? not a valid result.
My new, correct (I think) explanation:
//initial input: anagram("", "abc")
//STEP 1: enter the function --> i = 0 for original string "abc"
//anagram("" + "a", "bc") ----> anagram("a", "bc")
//STEP 2: loop through the new, modified string, which is now "bc"
//var i = 0;
//anagram("a" + "b", "c")---> anagram("ab", "c")
//anagram("ab" + "c", [nothing here])
//base case hit, so uniqueOutput["abc"] = 1;
//var i = 1; --> this applies to the string "bc". the loop gets reset to i = 0 once you have a new string to worth with (like below, with "b")
//anagram("a" + "c", "b")
//anagram("ac", "b")
//anagram("ac" + "b", "" )
//base case hit, so uniqueOutput["acb"] = 1;
//STEP 3: increment up on the original string input ("abc") --> so now you are dealing with str[i] === b
//var i = 1;
//anagram("" + "b", "a" + "c")
//anagram("b", "ac") ---> now we need to loop through "ac"!
//anagram("b" + "a", "c")
//anagram("ba", "c")
//anagram("bac", "")---> base case hit, uniqueOutput["bac"] = 1;
//anagram("b", "ac")
//anagram("b" + "c", "a") ---> anagram("bc", "a")
//anagram("bca", "") ---> base case hit, uniqueOutput["bca"] = 1;
//STEP 4: increment up on the original string input ("abc") ---> str[i] === c
//var i = 2;
//anagram ("" + "c", "ab")---> anagram("c", "ab")
//now we need to loop through "ab!" c's index stays the same.
//anagram("c" + "a", "b") ---> anagram("ca", "b")
//anagram("cab", '')---> uniqueOuput["cab"] = 1;
//anagram("c" + "b", "a") ---> anagram("cb", "a")
//anagram("cba", "")----> uniqueOutput["cba"] = 1
From your comments above:
// first iteration: i = 0
// anagram('' + 'a' + 'bc' [from str.slice(0 +1)]) ---> resolves to "abc") --->
Actually on i = 0, the arguments passed to anagram are:
anagram('' + 'a', '' + 'bc');
which evaluates to:
anagram('a', 'bc');
Then within that call to anagram, we again loop over str, which is now just 'bc'. That will result in 2 more calls to anagram which will be
anagram('a' + 'b', '' + 'c'); // i = 0
anagram('a' + 'c', 'b' + ''); // i = 1
which evaluate to:
anagram('ab', 'c');
anagram('ac', 'b');
And the second one of those calls will result in another call to anagram with these arguments:
anagram('acb', '');
which gets added to uniqueOutput as str is now empty.
Only after all that has executed will the code return to the outermost call of anagram and i will increment as per your comment:
//second iteration: i = 1. we are still in the original call from line 37.
You are missing the second iteration.. this is the execution flow in comments:
// anagram('', 'abc') level 0
// condition false... level 0
// first iteration: i = 0 level 0
// anagram(a', 'bc') ( creating new execution context level 1 )
// condition false.. level 1
// iteration 1... level 1
// anagram('ab', 'c') ( creating new execution context level 2 )
// condition false.. level 2
// iteration 1... level 2
// anagram('abc', '') ( creating new execution context level 3 )
// condition true.. push "abc"
// end for of level 2 context execution
// iteration 2... level 1
// anagram('ac', 'b') ( creating new execution context level 2 )
// condition false.. level 2
// iteration 1... level 2
// anagram('acb', '') ( creating new execution context level 3 )
// condition true.. push "abc" level 3
// end for of level 2 execution
// end for of level 1
// second iteration of level 0....
// keep this pattern till end for of level 0..
// end anagram level 0
As you can see, each iteration of the level 0 is going to push 2 words to the object. If we follow your logic, each iteration is pushing just one, take into consideration that recursion is just like adding more code in that exact place, once the function call finishes the execution flow returns to the place where it was before the call of the function.
Related
I have this JavaScript:
var str = "abcdefoihewfojias".split('');
for (var i = 0; i < str.length; i++) {
var xp = str[i] = "|";
}
alert( str.join("") );
I aim to replace every fourth letter in the string abcdefoihewfojias with |, so it becomes abc|efo|....etc,but I do not have a clue how to do this.
You could just do it with a regex replace:
var str = "abcdefoihewfojias";
var result = str.replace(/(...)./g, "$1|");
console.log(result);
To support re-usability and the option to wrap this in an object/function let's parameterise it:
var str = "abcdefoihewfojias".split('');
var nth = 4; // the nth character you want to replace
var replaceWith = "|" // the character you want to replace the nth value
for (var i = nth-1; i < str.length-1; i+=nth) {
str[i] = replaceWith;
}
alert( str.join("") );
This might help you solve your problem
var str = "abcdefoihewfojias".split("");
for (var i = 3; i < str.length - 1; i+=4) {
str[i] = "|";
}
alert( str.join("") );
You go with for loop from the the first char that you want to replace (the 3 char) until the one digit before the end and replace every 4 places.
If the for loop will go from the str.length and not to str.length-1 sometimes at the last char will be |.
.map one-liner
You can use this one-liner:
var str = "abcdefoihewfojias";
str.split('').map(function(l,i) {
return (i + 1) % 4 ? l : '|';
}).join('');
% returns the remainder. So:
# | Result (# + 1) % 4
---|-------
0 | 1
1 | 2
2 | 3
4 | 0 // Bingo!
ES6 alternative
With ES6, you can do:
[...str].map((l,i) => (i + 1) % 4 ? l : '|')
Simple just use modulus
https://jsfiddle.net/ctfsorwg/
var str = "abcdefoihewfojias";
var outputStr = str.split("");
for (var i = 0; i < outputStr.length; i++) {
if(!((i+1)%4))outputStr[i] = '|';
}
alert( "Before: " + str + "\nAfter: " + outputStr.join(""));
While there are several answers already, I thought I'd offer a slightly alternative approach, using Array.prototype.map(), wrapped in a function that can be adapted by the user (to update the value of n in the nth character, and change the replacement character used):
// defining the named function, with an 'opts' argument:
function replaceNthWith(opts) {
// setting the default options:
var defaults = {
// defining the nth character, in this case
// every fourth:
'nth': 4,
// defining the character to replace that
// nth character with:
'char': '|'
};
// Note that there's no default string argument,
// so that one argument must be provided in the
// opts object.
// iterating over each property in the
// opts Object:
for (var property in opts) {
// if the current property is a property of
// this Object, not inherited from the Object
// prototype:
if (opts.hasOwnProperty(property)) {
// we set that property of the defaults
// Object to be equal to that property
// as set in the opts Object:
defaults[property] = opts[property];
}
}
// if there is a defaults.string property
// (inherited from the opts.string property)
// then we go ahead; otherwise nothing happens
// note: this property must be set for the
// function to do anything useful:
if (defaults.string) {
// here we split the string supplied from the user,
// via opts.string, in defaults.string to form an
// Array of characters; we iterate over that Array
// with Array.prototype.map(), which process one
// Array and returns a new Array according to the
// anonymous function supplied:
return haystack = defaults.string.split('').map(function(character, index) {
// here, when the index of the current letter in the
// Array formed by Array.prototype.split() plus 1
// (JavaScript is zero-based) divided by the number
// held in defaults.nth is equal to zero - ensuring
// that the current letter is the 'nth' index we return
// the defaults.char character; otherwise we return
// the original character from the Array over which
// we're iterating:
return (index + 1) % parseInt(defaults.nth) === 0 ? defaults.char : character;
// here we join the Array back into a String, using
// Array.prototype.join() with an empty string:
}).join('');
}
}
// 'snippet.log()' is used only in this demonstration, in real life use
// 'console.log()', or print to screen or display in whatever other
// method you prefer:
snippet.log( replaceNthWith({ 'string': "abcdefoihewfojias" }) );
function replaceNthWith(opts) {
var defaults = {
'nth': 4,
'char': '|'
};
for (var property in opts) {
if (opts.hasOwnProperty(property)) {
defaults[property] = opts[property];
}
}
if (defaults.string) {
return haystack = defaults.string.split('').map(function(character, index) {
return (index + 1) % parseInt(defaults.nth) === 0 ? defaults.char : character;
}).join('');
}
}
// 'snippet.log()' is used only in this demonstration, in real life use
// 'console.log()', or print to screen or display in whatever other
// method you prefer.
// calling the function, passing in the supplied 'string'
// property value:
snippet.log( replaceNthWith({
'string': "abcdefoihewfojias"
}) );
// outputs: abc|efo|hew|oji|s
// calling the function with the same string, but to replace
// every second character ( 'nth' : 2 ):
snippet.log( replaceNthWith({
'string': "abcdefoihewfojias",
'nth': 2
}) );
// outputs: a|c|e|o|h|w|o|i|s
// passing in the same string once again, working on every
// third character, and replacing with a caret ('^'):
snippet.log( replaceNthWith({
'string': "abcdefoihewfojias",
'nth': 3,
'char' : '^'
}) );
// outputs: ab^de^oi^ew^oj^as
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
References:
Array.prototype.map().
Array.prototype.join().
for...in loop.
JavaScript Remainder (%) operator.
Object.prototype.hasOwnProperty().
String.prototype.split().
function replaceWith(word,nth, replaceWithCh) {
//match nth position globally
//'\S' is for non-whitespace
let regex = new RegExp("(\\S{" + (nth - 1) + "})\\S", "g");
// '$1' means single group
// after each group position replaceWithCharecter
let _word = word.replace(regex, "$1" + replaceWithCh);
return _word;
}
const str = "abcdefoihewfojias";
const result = replaceWith(str, 3, "X");
console.log(result);
I'm trying to run a program called IsSubArray. There are 2 input textboxes. One is called the big array and the other is called the sub array. The task is to check whether the values in sub array consecutively matches the numbers in big array. For example:
Array 1: 1,3,6,5,4
Array 2: 1,3,6 - true because 1,3 is matching with array 1.
Array 2: 1,6 - false because after 1, its 3 in array 1 not 6. It should match consecutively.
Array 2: 6,5,4 - true.
Array 2: 5,4,7 - false because is no number 7 after 4 in array 1.
But I am getting true for this last statement. I am unable to figure out why. I am just now learning algorithms.
Thanks in advance :)
function IsSubArray() {
inputArray1 = document.getElementById("inputText1").value.split(",");
inputArray2 = document.getElementById("inputText2").value.split(",");
var k = 0;
var msg = false;
for (j = 0; j < inputArray2.length - 1; j++) {
if (j > 0 && msg == false)
break;
//if (j > 0 && k == 0) {
// msg = false;
// break;
//}
for (i = 0; i < inputArray1.length - 1; i++) {
if (inputArray2[j] == inputArray1[i] && inputArray2[j + 1] != inputArray1[i + 1]) {
msg = false;
break;
}
else if (inputArray2[j] == inputArray1[i] && inputArray2[j + 1] == inputArray1[i + 1]) {
msg = true;
break;
}
//if (inputArray2[j] == inputArray1[i])
// k = 1;
}
}
document.getElementById("output").value = msg + " : LongArray: " + inputArray1 + " , ShortArray: " + inputArray2;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<input id="inputText1" type="text" />
<input id="inputText2" type="text" />
<br /><br />
<input id="IsSubArrayBtn" type="button" value="IsSubArray" onclick="IsSubArray()" />
<br /><br />
<input id="output" type="text" />
<script src="js/LogicalLoopings.js"></script>
</body>
</html>
The code seems overly complex. The general approach would be:
Find first element of subarray in array to get a starting point.
Verify that every element in subarray matches the following elements in array (at the starting point).
Repeat until there are no elements left to check.
Example implementation:
function contains(arr, subarray) {
const first = subarray[0];
// labeled loop so we can jump there easily
// find the "next" starting point for comparing the sequences
outer: for (let i = arr.indexOf(first); i > -1; i = arr.indexOf(first, i+1)) {
// When we find a starting point, compare the remaining elements in subarray
for (let j = 1; j < subarray.length; j++) {
if (arr[i+j] !== subarray[j]) {
// no need to continue checking the current sequence
// if one of the elements doesn't match
continue outer;
}
}
// if we made it through the inner loop then the sequences must be equal
return true;
}
// if we get here then `subarray` is not a sequence in `arr`
return false;
}
const arr = [1,3,6,5,4];
console.log(contains(arr, [1,3,6]));
console.log(contains(arr, [1,6]));
console.log(contains(arr, [6,5,4]));
console.log(contains(arr, [5,4,7]));
Array 2: 5,4,7 - false because is no number 7 after 4 in array 1. But I am getting true for this last statement. I am unable to figure out why.
You can add log statements to your code and see what actually happens. The problem is related to the fact that you are never iterating over all elements (i < inputArray1.length - 1) and that you are setting msg to true whenever two consecutive elements match.
The input is:
inputArray1 = [1,3,6,5,4]
// index i 0 1 2 3 4
inputArray2 = [5,4,7]
// index j 0 1 2
At some point you are comparing
inputArry2[0] == inputArry1[3] && inputArry2[1] == inputArry1[4]
// 5 == 5 && 4 == 4
which is true, so you set msg to true. Now the inner loop is done, because it stops when i === 3.
A new outer loop starts, where j = 1, so inputArry1[j] === 4. The first part of your if condition (inputArry2[j] == inputArry1[i]) is never fulfilled because i never has the value 4, so you are never comparing against the last element of inputArray1.
That means that msg is never assigned a new value and remains true.
check whether the values in sub array consecutively matches the numbers in big array
You can simplify the problem by using Array.join() and String.search():
const arr = [1, 3, 6, 5, 4]
/* test */
console.log(isSubArray(arr, [1,3,6])) // true
console.log(isSubArray(arr, [1,6])) // false
console.log(isSubArray(arr, [6,5,4])) // true
console.log(isSubArray(arr, [5,4,7])) // false
console.log(isSubArray(arr, [54])) // false
function isSubArray(original, guess) {
const a = original.join()
const b = guess.join()
return a.search(b) >= 0
}
I have what I think surely is a really simple question for most of you. But I have some trouble to get my head around this for loop. What does the -1 in argument.length -1 stand for? Is it the last item? And the i-- that is for decrease by 1?
var plus = function() {
var sum = 0;
for (var i = arguments.length - 1; i >= 0; i--) {
sum += arguments[i];
}
return sum;
}
console.log(plus(2,2,3,657,5643,4465,2,45,6));
When you call arguments.length It will return you the number of elements with the last one accessed with arguments[arguments.length-1] because counting starts with 0.
(the First element is accessed like this arguments[0]).
Here is good documentation for Java but it is the same for JavaScript: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
And yes i-- decreases i for 1. It is different i-- and --i.
Using ++/-- After the Operand
When you use the increment/decrement operator after the operand, the value will be returned before the operand is increased/decreased.
Check out this example:
// Increment
let a = 1;
console.log(a++); // 1
console.log(a); // 2
// Decrement
let b = 1;
console.log(b--); // 1
console.log(b); // 0
When we first log out the value of a, or b, neither has changed. That’s because the original value of the operand is being returned prior to the operand being changed. The next time the operator is used, we get the result of the +1, or -1.
Using ++/-- Before the Operand
If you’d rather make the variable increment/decrement before returning, you simply have to use the increment/decrement operator before the operand:
// Increment
let a = 1;
console.log(++a); // 2
console.log(a); // 2
// Decrement
let b = 1;
console.log(--b); // 0
console.log(b); // 0
As you can see in the above example, but using ++ or -- prior to our variable, the operation executes and adds/subtracts 1 prior to returning. This allows us to instantly log out and see the resulting value.
The - 1 means to subtract 1 from arguments.length. i-- means to decrease i by 1.
You need to know two things here:
arguments is a object type so it has key-value pair of values you passed as a argument into a function. Furthermore, the arguments object is not an Array. It is similar to an Array, but does not have any Array properties except length.
The key of arguments always starts with 0 and ends with one value less than the length of arguments. See the example below the key ends at 8 so you do arguments.length - 1 so that you get 8 instead of 9.
And since you are looping considering the last value first in arguments you do --i.
var plus = function() {
console.log(arguments);
console.log(typeof arguments);
var sum = 0;
for (var i = arguments.length - 1; i >= 0; i--) {
sum += arguments[i];
}
return sum;
}
console.log(plus(2, 2, 3, 657, 5643, 4465, 2, 45, 6));
Alternatively, you can also do i++ as,
var plus = function() {
var sum = 0;
for (var i = 0; i <arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
console.log(plus(2, 2, 3, 657, 5643, 4465, 2, 45, 6));
var levelOrder = function(root) {
const arr = [];
function traverse(node, level) {
if (!node) return;
if(arr[level] === undefined) {
arr[level] = [];
arr[level].push(node.val)
} else {
arr[level].push(node.val)
}
traverse(node.left, level + 1);
traverse(node.right, level + 1);
}
traverse(root, 0);
return arr;
};
In the recursion call to traverse function. Using
traverse(node.left, level + 1);
gives me the correct answer but
traverse(node.left, ++level);
gives me incorrect answer.
Let's say level is currently 0. My hypothesis is that the first example will feed 1 as the second argument to the traverse function. Second example will assign 1 to level (level = level + 1) and feed level(which is 1) as the second argument to the traverse function.
Lets assume level = 5;
level + 1 is an expression that returns the value 6 and doesn't change the value of level at all, so its value is still 5.
++level is an expression that increments that value of level to 6 and then returns the value of level which is now 6.
Twice in a row like in your function:
level + 1; // returns 6
level + 1; // returns 6
And now the other way:
++level; // returns 6
++level; // returns 7
That's why it's failing.
I'm trying to rewrite this frequency finding program in Javascript. Here is the Java code:
public class frequency {
public static void main(String[] args){
String S = "Temple University";
int[] p = new int[256];
for (char c :S.toCharArray()) {
p[c]++;
System.out.println(c +" shows up "+p[c] + " times");
}
Output:
T shows up 1 times
e shows up 1 times
m shows up 1 times
p shows up 1 times
l shows up 1 times
e shows up 2 times
shows up 1 times
U shows up 1 times
n shows up 1 times
i shows up 1 times
v shows up 1 times
e shows up 3 times
r shows up 1 times
s shows up 1 times
i shows up 2 times
t shows up 1 times
y shows up 1 times
However, my JavaScript implementation doesn't work at all:
function frequency(){
s = "Temple University";
str = s.split('');
p = [];
p.length = 256;
console.log("start");
for(c in str){
p[c]++;
console.log("inside" + c);
console.log(String.fromCharCode(c) + " shows up " + p[c] + "times");
}
}
It's late I've been trying to figure out why this JavaScript code is not working so I'm sorry if this post seems unpolished.
You can manipulate string directly as array and need a safe check for occurrence of chars else assign value 1.
So use a for loop for iterating over whole string can extract char as s[index] while using p[char] for occurrence frequency.
sample code follows
function frequency(){
s = "Temple University";
p = [];
console.log("start");
for(var i=0;i<s.length;i++){
if(!p[s[i]]){
p[s[i]] = 1;
}else{
p[s[i]]++;
}
console.log(s[i] + " shows up " + p[s[i]] + "times");
}
}
frequency()
Does this work for you? If so, you just weren't referencing the charCode but the index of the letter in the string..
function frequency() {
s = "Temple University";
str = s.split('');
p = [];
p.length = 256;
console.log("start");
for (c in str) {
var curChar = str[c];
var charCode = curChar.charCodeAt();
p[charCode] ? p[charCode]++ : p[charCode] = 1;
console.log(curChar + " shows up " + p[charCode] + " time(s)");
}
}
frequency()
The main reason this isn't working is that for loops work differently in Javascript than in Java. In Javascript, a for-in loop iterates through the properties of an object, not the indices of an array or string, so rather than for-in, you'd want to use a plain for loop, like so:
function getFrequencies(string) {
if (typeof(string) !== 'string') {
throw new Error('string argument is not of type string.');
}
var str = string.split('');
var frequencies = {};
for (var c = 0; c < str.length; c++) {
var charCode = String.fromCharCode(str[c]);
if (!frequencies[charCode]) {
frequencies[charCode] = 1;
} else {
frequencies[charCode]++;
}
}
return frequencies;
}
A couple tips: you would want to use a plain object ({}) instead of an array ([]), given that you're counting unique values. Secondly, there's no need to declare the length of an array in Javascript -- arrays are automatically resized as they grow, and the length property is readonly anyway.
You may do as follows;
var s = "Temple University",
fmap = Array.prototype.reduce.call(s,(p,c) => (p[c] ? p[c]++ : p[c] = 1,p),{});
for(var i in fmap) console.log(i, "shows up", fmap[i],"times.");
We are using an array functor Array.prototype.reduce() over a string by using a Function method .call(). So the first argument passed to .call() is the string s itself (designating the context to be called upon) and a callback ((p,c) => (p[c] ? p[c]++ : p[c] = 1,p)) for the second argument to be invoked per item (character) of the string. The .reduce() functor uses an empty object {} as an initial value which will be assigned to p, whereas c would be assigned to the first character in the first turn. It will generate a map called fmap like;
{ T: 1,
e: 3,
m: 1,
p: 1,
l: 1,
' ': 1,
U: 1,
n: 1,
i: 2,
v: 1,
r: 1,
s: 1,
t: 1,
y: 1 }
Then a for in loop traverses over the map keys and we display the obtained data by a console.log() instruction.