Learning JavaScript - for-in statement with a max. result - javascript

I'm reading a book about JS, and I'm stuck with one of the excercises.
I wrote a for-in to display the browser properties.
for (var i in navigator) {
document.getElementById('divResult').innerHTML += i + ': ' + navigator[i] + '<br />';
};
Now is the question how can I display only the first 10 of the navigator properties?
Thnx for helping me out!

You're using an object, and unlike an array objects don't have a "length" property that lets you easily run a loop over them. There are lots of ways to do this, but the easiest way to understand when you're learning is to create a "counter" variable outside expression and check to see if its true:
var counter = 0;
for (var i in navigator)
{
if ( counter <= 10 )
{
document.getElementById('divResult').innerHTML += i + ': ' + navigator[i] + '<br />';
counter = counter + 1;
}
};
There are other ways to cause the expression to stop, as mentioned above, but this (for me) was the easiest way to think about things when I started

Increment a counter, quit the loop when it hits 10
var i = 0;
for (var k in navigator) {
i++;
document.getElementById('divResult').innerHTML += i + ', ' + k + ': ' + navigator[k] + '<br />';
if (i === 10)
break;
};

Related

How to know when a for loop is done without knowing how many iterations there will be?

using a for-loop in javascript i´m getting a not known amount of id´s, they´re not in an array but coming one by one.
is there a way to get an alert when there are no more id´s to retrieve meaning the for loop is done?
i can´t wrap my head around this, any help would be greatly appreciated.
thanks!
edited with code for clarification.
function iterateDevices(api) {
var count = api.getcount("devices"); var apiPath = dequotePath(api);
for (var i = 0; i < count; i++) {
var deviceApi = new LiveAPI(apiPath + " devices " + i); if (deviceApi) {
var deviceName = deviceApi.get("name"); var deviceid = deviceApi.id; //var
deviceName = deviceApi.get("parameters"); var className =
deviceApi.get("class_name"); var deviceApiPath = dequotePath(deviceApi);
var chainsCount; var chainApi; var j;
if ((className == "DrumGroupDevice") || (className ==
"AudioEffectGroupDevice") || (className == "InstrumentGroupDevice")){
//post(deviceName + " id " + deviceid + "\'\n"); //outlet(0,deviceid);
// arr.push(deviceName);
if (deviceApi.get("can_have_chains") == 1) { chainsCount =
deviceApi.getcount("chains"); // only racks have chains for (j = 0; j
< chainsCount; j++) { // post("id" + deviceid + " found device " +
deviceName + " at path \'" + deviceApiPath + "\'\n");
//outlet(0,deviceid); chainApi = new LiveAPI(deviceApiPath + " chains
" + j); iterateDevices(chainApi);
myFunction(); } chainsCount = deviceApi.getcount("return_chains");
// only racks have chains for (j = 0; j < chainsCount; j++) {
//post("2 found device " + deviceName + "id"+deviceid + " at path
\'" + deviceApiPath + "\'\n"); // outlet(0,deviceid); chainApi = new
LiveAPI(deviceApiPath + " return_chains " + j);
iterateDevices(chainApi);
}
}
}
}
}
} iterateDevices.local = 1;
The purpose of a for loop is to deal with a known number of iterations. If you want to deal with an unknown number of iterations, you would use a while loop.
Of course, this is programming, so lets look at the crazy things we can do:
Iterate over a collection. We dont necessarily know how many things
are in the collection, but we may want to iterate over all of them.
The number of things in the collection might even change as we're
iterating.
We can change how we iterate through the loop. That whole i++ part?
What if we replace it with i += 2? Or what if it's i -=1? Or i += j
and j changes while we're iterating?
We can change how we break out of the loop. You can put a break
statement in there to break out of the loop anytime. You can also
change the conditional of the loop. What if i < 100 is replaced by
i<j? Or what if we replace it with i<100 || q == true?
You may use a while loop instead of a for and insert a condition to terminate the loop.
Using pseudo-code, you could do something like:
other_ids = True // boolean var
while(other_ids) {
// do what you have to do
other_ids = FuncionToCheckWhetherThereAreNewIds
}
FuncionToCheckWhetherThereAreNewIds should be a function that gives you true if there are new ids and false if there are not.

Nested for loop updating 3 variables at the same time

I have looked around, but found no solution.
I want to print out the 'interpolation' points between this:
.card.ani25 {
bottom: 72%;
left:85%;
}
and this:
.card.ani49 {
bottom: 46%;
left: 46%;
}
Basically, I am trying to update all numerical values in that CSS at the same time. Updating one value at a time works, but is of no use in this case.
What I have tried so far, well, everything coming to mind, including triggering some infinite loops, but this is what is "stable":-)
for (var i = 25; i < 50; i++){
for (var j = 72; j >=46; j-=2){
for (var k = 85; k >=46; k-=3){
t.innerHTML = '.card.ani' + i + ' {' + '<br>' + 'bottom: ' + j + '%;' + '<br>' + 'left: ' + k + '%;' + '<br>' + '}';
}
}
}
This only prints out the final iteration, as can be seen here:
http://codepen.io/damianocel/pen/ZLEXOR
If I put a += after the "innerHTML2, it blows up, screen freezes, just like an infinite loop.
I know, the outermost loop runs first, then the next inner loop second multiple times, but I have never seen a case with 3 variables. Honestly, I wouldn't know the solution for 2 variables only either.
Thanks and very sorry if this has been asked before.
The problem is is that the operation for changing HTML through reassigning innerHTML is slow. When you use += it will rewrite the HTML each time, that's what's causing it to slow down. That said it still works, a faster way to do this is use a variable to hold the string and update that variable. Then at the end assign the value of t.innerHTML to that string:
var t = document.getElementById('target');
var str = "";
for (var i = 25; i < 50; i++){
for (var j = 72; j >=46; j-=2){
for (var k = 85; k >=46; k-=3){
str += '.card.ani' + i + ' {' + '<br>' + 'bottom: ' + j + '%;' + '<br>' + 'left: ' + k + '%;' + '<br>' + '}';
}
}
}
t.innerHTML = str;
Edit
After clarification it appears you only want a single loop and update the variables each time in that loop. In that case you can do something like:
var t = document.getElementById('target');
var str = "";
for (var i = 25, j = 72, k = 85; i < 50 && j >=46 && k >=46; i++, j-=2, k-=3){
str += '.card.ani' + i + ' {' + '<br>' + 'bottom: ' + j + '%;' + '<br>' + 'left: ' + k + '%;' + '<br>' + '}';
}
t.innerHTML = str;
For each section inside a for loop for(x;y;z) you can use a comma to make many statements. So in the first section you can define 3 variables and in the last section update 3 variables. The middle section runs the loop as long as all of those conditions are met, when a single one fails it stops.
Note: You can use || (OR) if you would like it to keep going as long as one of the conditions are true.
Code Pen (single loop)
Code Pen
I'd promote a very different approach.
I think of this as a number of distinct ranges that need to be animated over in parallel. So I would like to have a function that knows how to do just that.
const rangeFns = (...configs) => fn => val =>
fn.apply(null, configs.map(cfg => (cfg.end - cfg.start) * val + cfg.start))
This takes a collection of range descriptions and returns a function that accepts a custom function with one parameter for each of those ranges and finally returns a simple function that accepts a number between 0 and 1, returning the result of your custom function with the interpolation for each range being supplied for the respective parameter. That's a bit of a mouthful, but I think it's easy to use:
const anim = rangeFns(
{start: 25, end: 49},
{start: 72, end: 46},
{start: 85, end: 46}
)((ani, bottom, left) => `
.card.ani${Math.round(ani)} {
bottom: ${bottom}%;
left: ${left};
}`
);
If you ran this with values 0, 0.25, 0.5, 0.75, and 1, you'd get these results:
.card.ani25 {
bottom: 72%;
left: 85;
}
.card.ani31 {
bottom: 65.5%;
left: 75.25;
}
.card.ani37 {
bottom: 59%;
left: 65.5;
}
.card.ani43 {
bottom: 52.5%;
left: 55.75;
}
.card.ani49 {
bottom: 46%;
left: 46;
}
(Obviously you could add rounding to bottom and left if that's desired.)
You could then use this in an animation, by passing values calculated from your start and finish times.
To my mind the advantage is that this is more explicit. It makes the ranges more declarative, and makes the function that uses the results a lot more straightforward.
A version of this is available on Codepen.
Update
A slightly better version of this would be to use arrays rather than objects. (I originally had additional parameters in there that turned out unnecessary. I didn't notice that removing them allowed for a nice clean-up.)
const multiRange = (...ranges) => fn => val =>
fn.apply(null, ranges.map(range => (range[1] - range[0]) * val + range[0]))
const anim = multiRange([25, 49], [72, 46], [85, 46])((ani, bottom, left) => `
.card.ani${Math.round(ani)} {
bottom: ${bottom}%;
left: ${left};
}`
);
I think this reads better.
This version is also on Codepen.

Access the an objects keys and the index from an object in a for loop

I want to access the an object keys and the index from an object, what is the best way to do this?
this is data object:
d={KpiName:"KPI1", '1/1/2016':"85%", '1/2/2016':"87%"}
Object {KpiName: "KPI1", 1/1/2016: "85%", 1/2/2016: "87%"}
this is my for 1st loop with output
for (var key in d) { console.log("d[\"key\"]: ", d[key]) }
d["key"]: KPI1
d["key"]: 85%
d["key"]: 87%
this is what I want to achieve but I thought I could write it better
2nd for loop with output
i=1; for (var key in d) { console.log("d[\"key\"]: ", d[key]); console.log("i: ", i); i++}
d["key"]: KPI1
i: 1
d["key"]: 85%
i: 2
d["key"]: 87%
i: 3
3
I thought I could write the for loop like this
for (var key, i in d){...}
But it does not seem to work, maybe my 2nd for loop achieves what I want but I am not sure if it the best code.
If you want to use a for/in loop, there is no better way to write this. You have to keep your own loop variable to count the iterations.
You could use Object.keys to get an array of keys first and then access their index either by using a for loop or using forEach, but I wouldn't call this "better", it's just a different way to go about it:
var d = {KpiName:"KPI1", '1/1/2016':"85%", '1/2/2016':"87%"};
Object.keys(d).forEach(function(key, i) {
console.log("d[\"key\"]: ", d[key]);
console.log("i: ", i);
});
I don't know if I get your question correctly, but you can use Object.keys with forEach:
var d={KpiName:"KPI1", '1/1/2016':"85%", '1/2/2016':"87%"};
Object.keys(d).forEach(function(e, i){
console.log("the key is: " + e + ", the value is: " + d[e] + ", the index is: " + i)
})
I have created some code that will print nicely what you are looking for. The trick is to use Object.keys because it passes the index for you. Here is a clean snippet of code that looks like it supports your use case:
var d = { KpiName:"KPI1", '1/1/2016':"85%", '1/2/2016':"87%"}
Object.keys(d).forEach(function (key, index) {
if (index == 0) {
console.log(" ",key," ",d[key])
console.log("------------------------")
} else {
console.log( index + ". " + key + " "+d[key]);
}
});
// run then open console to view output
// KpiName KPI1
// ------------------------
// 1. 1/1/2016 85%
// 2. 1/2/2016 87%
I have provided a working example here: https://jsfiddle.net/h9yw48bz/
Please shoot me a +1 if you find this to be a helpful answer
There are so many options as below to achieve this as below.
Method 1:
If you target only the modern browsers and not an old IE you can use Object.keys as below:
var d = {KpiName:"KPI1", '1/1/2016':"85%", '1/2/2016':"87%"};
//var i = 0;
Object.keys(d).forEach(function(key, i){
console.log('d["' + key + '"]: ' + d[key]);
console.log('index: ' + (i++).toString());
});
Method 2:
If you target old browsers as well, you can use the same one you did above with a minor change not to include any inherited object properties:
var d = {KpiName:"KPI1", '1/1/2016':"85%", '1/2/2016':"87%"};
var i = 0;
for(var key in d) {
if(d.hasOwnProperty(key)){
console.log('d["' + key + '"]: ' + d[key]);
console.log('index: ' + (i++).toString());
}
}
Method 3:
Using Jquery
var d = {KpiName:"KPI1", '1/1/2016':"85%", '1/2/2016':"87%"};
var i = 0;
$.each(d, function(key, value) {
console.log('d["' + key + '"]: ' + value);
console.log('index: ' + (i++).toString());
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Method 4:
Using AngularJS
var d = {KpiName:"KPI1", '1/1/2016':"85%", '1/2/2016':"87%"};
var i = 0;
angular.forEach(d, function(value, key) {
console.log('d["' + key + '"]: ' + value);
console.log('index: ' + (i++).toString());
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

Printing out the average of values stored in an array, in a table

i'm trying to print out the average value in a table using javascript. Here is my code"
I have placed a for loop to loop through the array however, i only get the mean or average value as you would say of the last line of the array, for Khan.
Any help would be appreciated, thank you!
That's what this code does - assigning the last mean value.
You have to store mean values with the students, or calculate it when writing to document, i.e.:
document.write("<td>" + 0.5*(students[i].CW50 + students[i].EX50) + "</td></tr>")
instead of:
document.write("<td>" + mean + "</td></tr>")
You only have one mean variable and you set it three times in your first loop
for (var i = 0; i < 3; i++) {
var mean = 0.5*(students[i].CW50 + students[i].EX50)
}
So your calculation of three means has finished before placing the values anywhere and mean has the value of the last calculation (i=2, Khan) because you didn't use an array (something like mean[i] = ...).
Solution: You have to do the calculation in the second loop like:
for (var i=0; i<3; i++) {
var mean = 0.5*(students[i].CW50 + students[i].EX50);
document.write("<tr><td>" + students[i].name + "</td>");
document.write("<td>" + students[i].CW50 + "</td>");
document.write("<td>" + students[i].EX50 + "</td>");
document.write("<td>" + mean + "</td></tr>")
}
This way your calculation is done, the value is placed in the html and then the next iteration is processed.

Javascript: Reversing the loop ouput

Basically i'm creating a script to display the place value for set of numbers. Here's my script:
var arrn = '3252';
var temp = 0;
var q = arrn.length;
var j = 0;
for (var i = q-1; i >= 0; i--,j++) {
if (j!=0) temp = temp + ' + ';
{
temp += arrn[i] * Math.pow(10, j);
}
}
alert(temp);
My goal is to achieve 3000 + 200 + 50 + 2. But i get 2 + 50 + 200 + 3000. I tried temp.reverse() & sort functions but doesn't seem to work. Please help
Change
if(j!=0)temp=temp +' + ';
{
temp +=arrn[i]*Math.pow(10,j);
}
to
if(j!=0) {
temp=' + ' + temp;
}
temp = arrn[i]*Math.pow(10,j) + temp;
Live Example
Side note: Your braces in the first code block above are very misleading. What you have:
if(j!=0)temp=temp +' + ';
{
temp +=arrn[i]*Math.pow(10,j);
}
is
if(j!=0)temp=temp +' + ';
temp +=arrn[i]*Math.pow(10,j);
which is to say
if(j!=0) {
temp=temp +' + ';
}
temp +=arrn[i]*Math.pow(10,j);
the block in your version is not associated with the if, it's just a freestanding block.
Side note #2: Since you're using temp as a string everywhere else, I would initialize it with '' rather than with 0. Example The reason your string didn't end up with an extraneous 0 was really quite obscure. :-)
Just add the number to the beginning of the string instead of at the end:
for (var i = q - 1; i >= 0; i--, j++) {
if (j != 0) {
temp = ' + ' + temp;
}
temp = arrn[i] * Math.pow(10, j) + temp;
}
Demo: http://jsfiddle.net/Guffa/rh9oso3f/
Side note: You are using some confusing brackets in your code after the if statement. As there is a statement following the if statement, the brackets starting on the next line becomes just a code block, but it's easy to think that it's supposed to be the code that is executed when the condition in the if statement is true.
Another side note: the language attribute for the script tag was deprecated many years ago. Use type="text/javascript" if you want to specify the language.
How about temp.split("+").reverse().join(" + ")?
You can do this way. I know it can be optimised. But it works
var arrn='3252';
var temp=0;
var q=arrn.length;
var res = [];
var j=0;
for(var i=q-1;i>=0;i--,j++)
{
temp += parseFloat(arrn[i])*Math.pow(10,j);
res.push(arrn[i]*Math.pow(10,j));
}
res.reverse();
alert(res.join('+') + " = " + temp);
http://jsfiddle.net/he7p8y5m/
var arrn='3252';
var temp=new Array();
var q=arrn.length;
for(var i=0;i<=q-1; i++){
temp.push(arrn[i]*Math.pow(10,(q-i-1)));
}
temp = temp.join('+');
alert(temp);

Categories