var hash = "";
var count = 1;
var n = 3;
for (var pound = 1; pound <=7; pound ++)
{while (hash.length != count)
hash += "#";
hash += "\n";
count += n;
n ++;}
console.log(hash);
Hi, I'm new to Javascript and fairly new to coding in general. I've spend a couple of hours analyzing my code above. BTW, I generated myself without any assistance. I wouldn't say I'm proud because I dont know why or how it works. I guess I get the basic math behind the work and when I check the values of the variables at the final end, the results match my calculation. But I dont know exactly what happens. It generates a triangle using '#'. I've tried removing the For loop to see exactly what the while loop is doing but I cant get a hang of it. Please take a look.
At first, in the first For loop and coming into the while loop, the value of hash.length is 0. Comparing it to count which 1, they do not match and so nextline. After adding "#" and "\n", hash.length becomes 2. But the code is read to the end making var count now 4 and var n equal to 4 also.
Now, the next loop does not happen inside the while loop and I've tried this out myself. It goes back to the For Loop. Checking the condition of "hash.length != count", this condition still holds as hash.length is 2 and count is now 4. Since they are not equal, shouldn't the while take repeat before going back to the For loop again?
while (cond)
statement1;
statement2;
does not do what you think (and the indentation is lying to you). Reformating the code to be true to the logical flow gives you this:
var hash = "";
var count = 1;
var n = 3;
for (var pound = 1; pound <= 7; pound++) {
while (hash.length != count)
hash += "#";
hash += "\n";
count += n;
n++;
}
console.log(hash);
While repeats only the very next statement. If you need it to repeat more, you have to use a compound statement (statement block) using the curly braces.
Here, for loop will go once for each row; within that, while will go once for each hash character.
Any loop without brackets { <-code here-> } only loops looking the following line.
So your while is doing only this:
while (hash.length != count)
hash += "#";
So, removing your for loop, you will have hash = "#" (because count starts at 1, and hash.length is 0), and then the following will happen:
hash += "\n";
count += n;
n++;
Basically, hash will be # with a line break.
The answer to your question is that
since the while loop has no brackets to indicate the code inside the loop.
only one line, the
hash += "#";
gets execute, and when you get to the line that modifies the value of the count:
count += n;, the while loop wont repeat since you already exited that loop.
Usually you want to keep the code as simple as possible.
you can get the same result as the code you posted by simply writing it this way:
var hash="";
for (var pound = 1; pound <=7; pound ++)
{
hash += "#";
console.log(hash);
}
you will use far less variables, the length of hash will greatly be reduce.
sometimes too many string concatenation slows down code execution.
what the code above does is run a for loop seven times, each time, it appends a '#' to the hash string and displays it on the console...
same result, fewer lines, faster execution, and much easier to read.
if your are new to programming, I would recommend you start with a programming language the encourage good programming practice.
although PASCAL is not very popular anymore, learning it first before any C style language, would most likely get you up and running in writing very good code.
I know Pascal haters will probably criticize.. but, this language is good to get you to concentrate on algorithms and good programming style. which should be your first step before jumping into any language.
Related
I am looking to find the best possible way to find how many $ symbols are on a page. Is there a better method than reading document.body.innerHTML and calc how many $-as are on that?
Your question can be split into two parts:
How can we get the the webpage text content without HTML tags?
We can generalize the second question a bit.
How can we find the number of string occurrences in another string?
And the 'best possible way to do this':
Amaan got the idea right of finding the text, but lets take it further.
var text = document.body.innerText || document.body.textContent;
Adding textContent to the code helps us cover more browsers, since innerText is not supported by all of them.
The second part is a bit trickier. It all depends on the number of '$' symbol occurrences on the page.
For example, if we know for sure, that there is at least one occurrence of the symbol on the page we would use this code:
text.match(/\$/g).length;
Which performs a global regular expression match on the given string and counts the length of the returned array. It's pretty fast and concise.
On the other hand, if we're not sure if the symbol appears on the page at least once, we should modify the code to look like this:
if (match = text.match(/\$/g)) {
match.length;
}
This just checks the value returned by the match function and if it's null, does nothing.
I would recommend using the third option only when there is a large occurrence of the symbols in the page or you're going to perform the search many many times. This is a custom function (taken from here) to count the occurrence of the specified string in another string. It performs better than the other two, but is longer and harder to understand.
var occurrences = function(string, subString, allowOverlapping) {
string += "";
subString += "";
if (subString.length <= 0) return string.length + 1;
var n = 0,
pos = 0;
var step = (allowOverlapping) ? (1) : (subString.length);
while (true) {
pos = string.indexOf(subString, pos);
if (pos >= 0) {
n++;
pos += step;
} else break;
}
return (n);
};
occurrences(text, '$');
I'm also including a little jsfiddle 'benchmark' so you can compare these three different approaches yourself.
Also: No, there isn't a better way of doing this than just getting the body text and counting how many '$' symbols there are.
You should probably use document.body.innerText or document.body.textContent to avoid getting your HTML give you false positives.
Something like this should work:
document.body.innerText.match(/\$/g).length;
An alternate way I can think of, would be to use window.find like this:
var len = 0;
while(window.find('$') === true){
len++;
}
(This may be unreliable because it depends on where the user clicked last. It will work fine if you do it onload, before any user interaction.)
For this code:
var i = 0;
for (i < menuitem.length; i += 1;)
JSlint returns:
Expected a conditional expression and instead saw an assignment.
Expected an identifier and instead saw ')'.
And refuses to continues scanning.
This code works fine but what is wrong? How could I write this with an "if" statement? (if that is what jslint means).
Thanks for your help guys!
Yeah, JSLint is pretty vicious. As others have pointed out, you're not filling things in in the right places, but aside from that, JSLint requires that you put something in the initialization part of the for loop. There are a couple options you can do to make it play nice without messing with your logic, though. My favorite is to just reset i (even though it's already set):
var i = 0;
for (i = 0; i < menuitem.length; i += 1) {
/** do stuff **/
}
This make JSLint happy and also ensures that i gets reset if you decide to use it for another for loop in the same lexical scope. Another option is to just toss a null in there to fill the space (if you don't want to reset the value of i):
var i = 0;
for (null; i < menuitem.length; i += 1) {
/** do stuff **/
}
Both work fine and appease the ever-so-worrisome JSLint. However, no one will really care if you just leave the initialization part blank (aside from JSLint). You might try JSHint, as it's a bit more forgiving on this sort of thing.
Your for loop is kind of weird, the second part should be a condition for the loop, instead you have an assignment.
You must always have the parts in order (initialisation; condition; step).
var i = 0;
for (; i < menuitem.length; i += 1)
I just moved your semicolon from the end to the start. Alternatively, you can place the variable declaration and assignment inside the first part if you like.
for (var i = 0; i < menuitem.length; i += 1) {
// code
}
Or
var i = 0;
for (; i < menuitem.length; i += 1) {
// code
}
Found it! Here is the precise answer for validation:
var i;
for (i = 0; i < menuitem.length; i += 1) {
// code
}
var should be outside says jslint :s
From your code snippet, I'm going to assume that i is simply a variable used to control the number of cycles of your loop. The correct code would be
for (var i = 0; i < menuitem.length; i += 1) {
// code
}
That is the standardized declaration and syntax - at least for the languages I can think of right now. And that is really the point of this type of loop - for loops were designed this way so the author can simply write one line of code versus more if he/she wanted to do a while loop.
I am currently doing a big project (by big I mean, many processes) where every millisecond I save means a lot (on the long run), so I want to make sure I am doing it the right way.
So, what is the best way to ensure you will have an array greater than 1?
a) use indexOf(), then if result is different than -1, split()
b) split (regardless if characters exist), then do stuff ONLY if the
array.length is greater than 1
c) another not listed above
Using jsPerf, it appears that omitting .indexOf() is roughly 23% more efficient that including it over 500,000 iterations (11.67 vs. 8.95 operations per second):
Without indexOf():
var str = "test";
for (var i = 0; i < 500000; i++) {
var test = str.split('.');
}
With .indexOf():
var str = "test";
for (var i = 0; i < 500000; i++) {
if (str.indexOf('.')) {
var test = str.split('.');
} else {
var test = str;
}
}
http://jsperf.com/split-and-split-indexof
EDIT
Hmm... If the following line is:
if (str.indexOf('.') > -1)
http://jsperf.com/split-and-split-indexof-with-indexof-check
Or any other comparison, it's seemingly quite a bit faster (by about 69%).
The only reason I can think this is the case is that running .split() on every variable will perform two functions on each value (find, then separate), instead of just one when necessary. Note, this last part is just a guess.
We can see that even when there is something to split the best results come from doing the indexOf test against a value. Still the improvement is worse that the cases where 100% of items don't need a split. Thus as you have more items needing to be split testing returns less benefit (as would be expected). So it really depends on the use case since the extra code takes up memory and uses resources.
http://jsperf.com/split-and-split-indexof/2
(b) is obviously more efficient than (a) because split uses the same logic as indexOf and that logic will not need to be repeated if there are indeed more than 2 elements. i cannot think of a more efficient way.
I want to find the number of tabs at the beginning of a string (and of course I want it to be fast running code ;) ). This is my idea, but not sure if this is the best/fastest choice:
//The regular expression
var findBegTabs = /(^\t+)/g;
//This string has 3 tabs and 2 spaces: "<tab><tab><space>something<space><tab>"
var str = " something ";
//Look for the tabs at the beginning
var match = reg.exec( str );
//We found...
var numOfTabs = ( match ) ? match[ 0 ].length : 0;
Another possibility is to use a loop and charAt:
//This string has 3 tabs and 2 spaces: "<tab><tab><space>something<space><tab>"
var str = " something ";
var numOfTabs = 0;
var start = 0;
//Loop and count number of tabs at beg
while ( str.charAt( start++ ) == "\t" ) numOfTabs++;
In general if you can calculate the data by simply iterating through the string and doing a character check at every index, this will be faster than a regex/regular expression which must build up a more complex searching engine. I encourage you to profile this but I think you'll find the straight search is faster.
Note: Your search should use === instead of == here as you don't need to introduce conversions in the equality check.
function numberOfTabs(text) {
var count = 0;
var index = 0;
while (text.charAt(index++) === "\t") {
count++;
}
return count;
}
Try using a profiler (such as jsPerf or one of the many available backend profilers) to create and run benchmarks on your target systems (the browsers and/or interpreters you plan to support for your software).
It's useful to reason about which solution will perform best based on your expected data and target system(s); however, you may sometimes be surprised by which solution actually performs fastest, especially with regard to big-oh analysis and typical data sets.
In your specific case, iterating over characters in the string will likely be faster than regular expression operations.
One-liner (if you find smallest is best):
"\t\tsomething".split(/[^\t]/)[0].length;
i.e. splitting by all non-tab characters, then fetching the first element and obtaining its length.
I am sorry for the very newbie question, but this is driving me mad.
I have a word. For each letter of the word, the characters position in one array is found and then returns the character at the same position found in a parallel array (basic cipher). This is what I already have:
*array 1 is the array to search through*
*array 2 is the array to match the index positions*
var character
var position
var newWord
for(var position=0; position < array1.length; position = position +1)
{
character = array1.charAt(count); *finds each characters positions*
position= array1.indexOf(character); *index position of each character from the 1st array*
newWord = array2[position]; *returns matching characters from 2nd array*
}
document.write(othertext + newWord); *returns new string*
The problem I have is that at the moment the function only writes out the last letter of the new word. I do want to add more text to the document.write, but if I place within the for loop it will write out the new word but also the other text inbetween each word. What i actually want to do is return the othertext + newWord rather than document.write so that I can use it later on. (just using doc.write to text my code) :-)
I know its something really simple, but I cant see where I am going wrong. Any advice?
Thanks
Issy
The solution is to build newWord within the loop using += instead of =. Just set it to an empty string before the loop.
There are other problems with this code. Variable count is never initialized. But let's assume that loops should be using count instead of position as it's principal counter. In that case, if I am not mistaken, this loop will just generate array2 as newWord. First two lines of loop's body cancel each other in a matter of speaking, and position will always be equal to count, so letters from array2 will be used sequentially from beginning to the end.
Could you provide one example of input and desired output, so that we understand what you actually want to accomplish?
A good way of structuring your code and your question is that you define a function that you need to implement. In your case this could look like:
function transcode(sourceAlphabet, destinationAlphabet, s) {
var newWord = "";
// TODO: write some code
return newWord;
}
That way, you clearly state what you want and which parameters are involved. It is also easy to write automatic tests later, for example:
function testTranscode(sourceAlphabet, destinationAlphabet, s, expected) {
var actual = transcode(sourceAlphabet, destinationAlphabet, s);
if (actual !== expected) {
document.writeln('<p class="error">FAIL: expected "' + expected + '", got "' + actual + '".</p>');
} else {
document.writeln('<p class="ok">OK: "' + actual + '".');
}
}
function test() {
testTranscode('abcdefgh', 'defghabc', 'ace', 'dfh');
}
test();