for( in ) loop index is string instead of integer [duplicate] - javascript

This question already has answers here:
Why does javascript turn array indexes into strings when iterating?
(6 answers)
Is a JavaScript array index a string or an integer?
(5 answers)
Why is key a string in for ... in
(3 answers)
When iterating over values, why does typeof(value) return "string" when value is a number? JavaScript
(1 answer)
Closed 1 year ago.
Consider following code:
var arr = [111, 222, 333];
for(var i in arr) {
if(i === 1) {
// Never executed
}
}
It will fail, because typeof i === 'string'.
Is there way around this? I could explicitly convert i to integer, but doing so seems to defeat the purpose using simpler for in instead of regular for-loop.
Edit:
I am aware of using == in comparison, but that is not an option.

You have got several options
Make conversion to a Number:
parseInt(i) === 1
~~i === 1
+i === 1
Don't compare a type (Use == instead of ===):
i == 1 // Just don't forget to add a comment there
Change the for loop to (I would do this but it depends on what you are trying to achieve):
for (var i = 0; i < arr.length; i++) {
if (i === 1) { }
}
// or
arr.forEach(function(item, i) {
if (i === 1) { }
}
By the way you should not use for...in to iterate through an array. See docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in
for..in should not be used to iterate over an Array where index order
is important. Array indexes are just enumerable properties with
integer names and are otherwise identical to general Object
properties. There is no guarantee that for...in will return the
indexes in any particular order and it will return all enumerable
properties, including those with non–integer names and those that are
inherited.
Because the order of iteration is implementation dependent, iterating
over an array may not visit elements in a consistent order. Therefore
it is better to use a for loop with a numeric index (or Array.forEach
or the non-standard for...of loop) when iterating over arrays where
the order of access is important.

With === you compare also the type of values. Use == instead:
if ( i == 1 ) {}
or cast i to integer:
if ( +i === 1 ) {}
Also you can try with 'standard' for loop:
for (var i = 0; i < arr.length; i++) {
if (i === 1) {}
}

If you don't need browser support below IE9, you can use Array.forEach
If you do, use the good ol' for (i = 0; i < arr.length; i++) {} loop.

Is this what you mean?
var arr = [1, 2, 3];
for(var i in arr) { //i is not the value of an element of the array, but its "attribute name"
if(arr[i] === 1) {
}
}
In any case, I'd use the good old classic for syntax, it's the recommended way to deal with arrays

for-in loops properties in object, you could use for-of to loop array.
for (const i in [11, 22, 33, 44, 55]) {
console.log(`${typeof i}: ${i}`);
}
string: 0
string: 1
string: 2
string: 3
string: 4
const obj = {
11: 'a',
22: 'b',
33: 'c',
44: 'd',
55: 'e',
}
for (const i in obj) {
console.log(`${typeof i}: ${i} -> ${obj[i]}`);
}
string: 11 -> a
string: 22 -> b
string: 33 -> c
string: 44 -> d
string: 55 -> e
for (const i of [11, 22, 33, 44, 55]) {
console.log(`${typeof i}: ${i}`);
}
number: 11
number: 22
number: 33
number: 44
number: 55

Related

JS: Finding unpaired elements in an array

I have the following question (this is not school -- just code site practice questions) and I can't see what my solution is missing.
A non-empty array A consisting of N integers is given. The array contains an odd number of elements, and each element of the array can be paired with another element that has the same value, except for one element that is left unpaired.
Assume that:
*N is an odd integer within the range [1..1,000,000];
*each element of array A is an integer within the range [1..1,000,000,000];
*all but one of the values in A occur an even number of times.
EX: A = [9,3,9,3,9,7,9]
Result: 7
The official solution is using the bitwise XOR operator :
function solution(A) {
var agg = 0;
for(var i=0; i<A.length; i++) {
agg ^= A[i];
}
return agg;
}
My first instinct was to keep track of the occurrences of each value in a Map lookup table and returning the key whose only value appeared once.
function solution(A) {
if (A.length < 1) {return 0}
let map = new Map();
let res = A[0]
for (var x = 0; x < A.length; x++) {
if (map.has(A[x])) {
map.set(A[x], map.get(A[x]) + 1)
} else {
map.set(A[x], 1)
}
}
for ([key,value] of map.entries()) {
if (value===1) {
res = key
}
}
return res;
}
I feel like I handled any edge cases but I'm still failing some tests and it's coming back with a 66% correct by the automated scorer.
You could use a Set and check if deletion deletes an item or not. If not, then add the value to the set.
function check(array) {
var s = new Set;
array.forEach(v => s.delete(v) || s.add(v));
return s.values().next().value;
}
console.log(check([9, 3, 9, 7, 3, 9, 9])); // 7
You're not accounting for cases like this:
[ 1, 1, 2, 2, 2 ] => the last 2 is left unpaired
So your condition should be if ( value % 2 ) instead of if ( value === 1 ).
I think also there is not much benefit to using a Map rather than just a plain object.
The official solution works due to the properties of the bitwise XOR (^), namely the fact that a ^ a == 0, a ^ 0 == a, and that the operation is commutative and associative. This means that any two equal elements in the array will cancel each other out to become zero, so all numbers appearing an even amount of times will be removed and only the number with an odd frequency will remain. The solution can be simplified using Array#reduce.
function findOdd(arr) {
return arr.reduce((a,c)=>a ^ c, 0);
}
You need not to make a count of each and traverse again, if you are sure that there will be exactly one number which will occur odd number of times. you can sum the array and do + when odd entry and - when even entry (to dismiss it back) and in the hash (map or object) you can just toggle for subsequent entry of each number.
Here is an example:
let inputArray1 = [10,20,30,10,50,20,20,70,20,70,50, 30,50], //50 -> 3 times
inputArray2 = [10,20,30,20,10], //30 -> 1 time
inputArray3 = [7,7,7,7,3,2,7,2,3,5,7]; //5 -> 1 time
let getOddOccuence = arr => {
let hash = {};
return arr.reduce((sum, n) => sum + ((hash[n] = !hash[n]) ? n : -n), 0);
}
console.log('Input Array 1: ', getOddOccuence(inputArray1));
console.log('Input Array 2: ', getOddOccuence(inputArray2));
console.log('Input Array 3: ', getOddOccuence(inputArray3));
In case the input contains multiple or no numbers having odd number of occurance (if you are not sure there) then you have already the hash (and you can ignore performing sum) and return the keys of hash (where value is true (and not checking with %2 and then consider as truthy or false in case of you have count))
function solution(A) {
let result = 0;
for (let element of A) {
// Apply Bitwise XOR to the current and next element
result ^= element;
}
return result;
}
const unpaired = solution([9, 3, 9, 3, 9, 7, 9]);
console.log(unpaired);
Source: https://gist.github.com/k0ff33/3eb60cfb976dee0a0a969fc9f84ae145

Nested for loops and multidimensional arrays

I'm trying to get my head around how nested for loops work with multidimensional arrays in JavaScipt and I'm a bit stuck on one point.
Using a stock example
var arr = [[1,2], [3,4], [5,6]];
for (var i=0; i < arr.length; i++) {
for (var j=0; j < arr[i].length; j++) {
console.log(arr[i][j]);
}
}
This outputs 1 2 3 4 5 6 which is what I expected.
However if I add numbers to the end of the outer array:
var arr = [[1,2], [3,4], [5,6], 7, 8];
for (var i=0; i < arr.length; i++) {
for (var j=0; j < arr[i].length; j++) {
console.log(arr[i][j]);
}
}
I still get the same output of 1 2 3 4 5 6 ? ?
I am confused why 7 & 8 are not being picked up by the loop. Interestingly, if I use strings instead:
var arr = [["a","b"], ["c","d"], "y", "z"];
for (var i=0; i < arr.length; i++) {
for (var j=0; j < arr[i].length; j++) {
console.log(arr[i][j]);
}
}
The output is a b c d y z, which is what I expected. Why does it behave differently for strings?
As others have mentioned, your inner loop is all about iterating the arrays found in the top level (non-nested array). It makes the assumption that all the elements in the top-level array will be nested arrays, which isn't the case. (You need to make sure that you have an array before attempting to iterate through it.) Since 7 and 8 in the top level aren't arrays, arr[i].length returns undefined for numbers, but strings are "array like" objects and do have a length property. A string of "y" has a length of 1 and so the inner loop works because it starts from zero and obtains the character at position zero in the string "array" of "y", which is "y".
But, this is a good reason not to use traditional for loops with arrays when we now have Array.forEach(), which eliminates the need for indexes to be manually managed and allows us to access the value being enumerated directly without worrying about indexes.
var arr = [[1,2], [3,4], [5,6], 7, 8];
var output = "";
// Enumerate the top-level array:
arr.forEach(function(value){
// Check to see if the item is an array
if(value instanceof Array){
// If so, enuerate that nested array
value.forEach(function(nestedValue){
// Add the nested array's value to the output
output += nestedValue + " " ;
});
} else {
// Item is not an array, just add its value to the output
output += value + " ";
}
});
console.log(output);
Oh, and by the way, I realize that this is not what you were asking about, but just as an FYI, here's a way to obtain all the values without any loops:
console.log([[1,2], [3,4], [5,6], 7, 8].toString().split(",").join(" "));
String, Array, TypedArray, Map and Set are all built-in iterables, because each of their prototype objects implements an ##iterator method. While Number is not iterable:
const iterate = v => {
for (var i = 0; i < v.length; i++) console.log(v[i])
}
iterate([1, 'two', 777]) // iterates by element
iterate('abc') // iterates by symbol
iterate(123) // does not iterate
Here's how things look like in modern Javascript.
In respect to loops, all values can be divided into "iterable" and "non-iterable". Iterable are values that you can well... iterate - with the for..of loop.
for (let item of someIterableThing)
// use item
(You do not use bare for loops - for(var i...i < length) - for the iteration, because not every iterable has length and indexes.)
Conversely, if you do for...of with a non-iterable thing, you'll get an error.
Arrays and strings are examples of iterable values, numbers are non-iterable. So when you have
[ [1,2], [3,4], "foobar" ]
all items in this array are iterable and your nested loop will work. However, in
[ [1,2], [3,4], 999]
the last item is non-iterable, and the nested loop will fail.
There's no built-in way to tell if an unknown value is iterable, you have to write a function for this:
let isIterable = x => x && x[Symbol.iterator]
(see the dedicated topic).
Then, you can use the nested loop in a safe manner:
for (let item of array)
if (isIterable(item))
for (let subItem of item)
console.log(subItem)
else
console.log(item)
As a side note, there are lots of obsolete information about Javascript on the net. The language is evolving, and things that were fine 5 years ago, are considered bad practice nowadays. Unfortunately, most tutorials, books and teachers do not keep up, and still promote old practices, like using bare for loops.
(Since people asked why exactly bare for loops are bad, consider this example:
You have an array text containing strings and multiple functions that process this array. Programmer A writes these functions in the old-fashioned manner:
for (var i = 0; i < text.length; i++)
do_something_with(text[i]) // ;(
Programmer B writes them in the modern way:
for (let str of text)
do_something_with(str) // :)
Now, the text grows bigger and bigger and doesn't fit in memory anymore. So the system architect decided to replace it with a streamable file object that only yields one string at a time. Programmer A now has to rewrite all his 100 functions to adapt to the new interface:
for (var file = TextFile; !file.eof(); file.getNext())
do_something_with(file.currentLine)
which involves lots of pain, convulsions and headache.
Programmer B just enjoys her vacation.)
You have a double loop. When you are doing the statement console.log(arr[i][j]); you try first to go into the index i of the arr array in this part arr[i].
You then proceed to call the index of the value in the array with [j]. Because 7, and 8 are just numbers and not arrays they don't log.
This is the reason why the letters are logged:
var arr = [["a","b"], ["c","d"], "y", "z"];
for (var i=0; i < arr.length; i++) {
for (var j=0; j < arr[i].length; j++) {
/* console.log(arr[i][j]); */
}
}
var foo = "a";
var bar = foo[0];
console.log(bar);
Strings behave as arrays of characters that's why you get the letter returns itself when you call foo[0] it returns a.
Why does it behave differently for strings?
Because strings are treated as an array of characters.
A JavaScript string stores a series of characters like "John Doe". Each character can be accessed using an array index, and also has length method for getting the size of the string. Hence why your "y", "z" works but not 7, 8 as they are not an array.

Variable in for loop is a string [duplicate]

This question already has answers here:
Why does javascript turn array indexes into strings when iterating?
(6 answers)
Is a JavaScript array index a string or an integer?
(5 answers)
Why is key a string in for ... in
(3 answers)
When iterating over values, why does typeof(value) return "string" when value is a number? JavaScript
(1 answer)
javascript for loop counter coming out as string [duplicate]
(3 answers)
Closed 6 years ago.
I'm not sure if this is normal behavior, but running this:
for (var i in [1, 2, 3]) {
console.log(i + 1);
}
Results in this:
// 01
// 11
// 21
Could somebody please explain, why is var i being treated like a string in this situation and not if I do for (var i = 0; i < [1, 2, 3].length; i++)?
Its most likely because in this for loop style (for..in), it is treating i as a key, and since keys in objects are usually strings (yes, an array is a type of object in javascript), it is treating it as a String.
parseInt(i) works in this situation, but for good programming practice, you would want to use a for loop that looks similar to this:
var array = [1, 2, 3];
for (var i = array.length - 1; i >= 0; i--) {
// do work with each array element here
}
The reason is that for .. in iterates object properties ("keys"), even for arrays. The "keys" in this case are the "indexes" of the array but it's still just object keys. As all object keys are strings, i gets a string value.
I think you want the values of the array, not the keys. If you can't use ES6, Xorifelse's answer works, but if you can, there is for ... of that works exactly as you probably thought:
for (let i of [1, 2, 3]) {
console.log(i + 1);
}
There is also Array.prototype.forEach in ES5 and up:
[1, 2, 3].forEach(function(value, index) {
console.log(value + 1);
});
Using the in keyword you're looping over each key in the object and those are string types and when using the + operator on a string will cause it to do a concatenation assignment.
If you want to perform an arithmetic assignment both the left and the right value of the operator have to be an integer type. A solution would be to try to parse the string to an integer:
console.log(parseInt("0") + 1); // 1
However... You should be looping over the value instead:
var data = [1, 2, 3];
for(var key in data){
console.log('a: data['+ key + '] = ' + data[key]);
}
for (var i = 0; i < data.length; i++) {
console.log('b: data['+ i + '] = ' + data[i]);
}
data.forEach(function(value, index){
console.log('c: data[' + index + '] = ' + value);
});
You could use the ES6 method to loop over the value alone:
for(let v of [1, 2, 3]) {
console.log(v);
}
The drawback of this method is the incompatibility of older android devices since its a somewhat new standard.
If you're using jQuery, you can also take a look at $.each as it allows for a key, value iteration in a nice one-liner that is compatible with older devices.
$.each([1, 2, 3], function(index, value) {
console.log( index + ": " + value );
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
It's because i is a key/ index of every element, and it's string type.
So you are in fact concatenating string and int – the result is string.
That is because with the "in" keyword you traverse the keys of the object, not array indexes. However in this case, since the object is an array, the keys of the items in are indexes. And last, the keys in a for..in loop are strings.
So if you need numeric indexes of an array, you need to use a regular for loop.
var array = [0, 1, 2];
for (var i = 0; i < array.length; i++) {
console.log(i + 1);
}
Well when you use the for...in loop you're visiting each key from an object. Arrays are objects and their keys are numbers, but usually object keys are treated like strings.
If you want to convert the key to int, you can use parseInt function.
link!
for (var i in [1, 2, 3]) {
console.log(parseInt(i) + parseInt(1));
}

What is the difference between ( for... in ) and ( for... of ) statements?

I know what is a for... in loop (it iterates over the keys), but I have heard about for... of for the first time (it iterates over values).
I am confused about for... of loop.
var arr = [3, 5, 7];
arr.foo = "hello";
for (var i in arr) {
console.log(i); // logs "0", "1", "2", "foo"
}
for (var i of arr) {
console.log(i); // logs "3", "5", "7"
// it doesn't log "3", "5", "7", "hello"
}
I understand that for... of iterates over property values. Then why doesn't it log "3", "5", "7", "hello" instead of "3", "5", "7"?
Unlike for... in loop, which iterates over each key ("0", "1", "2", "foo") and also iterates over the foo key, the for... of does not iterate over the value of foo property, i.e., "hello". Why it is like that?
Here I console for... of loop. It should log "3", "5", "7","hello" but it logs "3", "5", "7". Why?
Example Link
for in loops over enumerable property names of an object.
for of (new in ES6) does use an object-specific iterator and loops over the values generated by that.
In your example, the array iterator does yield all the values in the array (ignoring non-index properties).
I found a complete answer at Iterators and Generators (Although it is for TypeScript, this is the same for JavaScript too)
Both for..of and for..in statements iterate over lists; the values
iterated on are different though, for..in returns a list of keys on
the object being iterated, whereas for..of returns a list of values
of the numeric properties of the object being iterated.
Here is an example that demonstrates this distinction:
let list = [4, 5, 6];
for (let i in list) {
console.log(i); // "0", "1", "2",
}
for (let i of list) {
console.log(i); // "4", "5", "6"
}
Another distinction is that for..in operates on any object; it serves
as a way to inspect properties on this object. for..of on the other
hand, is mainly interested in values of iterable objects. Built-in
objects like Map and Set implement Symbol.iterator property allowing
access to stored values.
let pets = new Set(["Cat", "Dog", "Hamster"]);
pets["species"] = "mammals";
for (let pet in pets) {
console.log(pet); // "species"
}
for (let pet of pets) {
console.log(pet); // "Cat", "Dog", "Hamster"
}
Difference for..in and for..of:
Both for..in and for..of are looping constructs which are used to iterate over data structures. The only difference between them is the entities
they iterate over:
for..in iterates over all enumerable property keys of an object
for..of iterates over the values of an iterable object. Examples of iterable objects are arrays, strings, and NodeLists.
Example:
let arr = ['el1', 'el2', 'el3'];
arr.addedProp = 'arrProp';
// elKey are the property keys
for (let elKey in arr) {
console.log(elKey);
}
// elValue are the property values
for (let elValue of arr) {
console.log(elValue)
}
In this example we can observe that the for..in loop iterates over the keys of the object, which is an array object in this example. The keys are 0, 1, 2 (which correspond to the array elements) and addedProp. This is how the arr array object looks in chrome devtools:
You see that our for..in loop does nothing more than simply iterating over these keys.
The for..of loop in our example iterates over the values of a data structure. The values in this specific example are 'el1', 'el2', 'el3'. The values which an iterable data structure will return using for..of is dependent on the type of iterable object. For example an array will return the values of all the array elements whereas a string returns every individual character of the string.
For...in loop
The for...in loop improves upon the weaknesses of the for loop by eliminating the counting logic and exit condition.
Example:
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (const index in digits) {
console.log(digits[index]);
}
But, you still have to deal with the issue of using an index to access the values of the array, and that stinks; it almost makes it more confusing than before.
Also, the for...in loop can get you into big trouble when you need to add an extra method to an array (or another object). Because for...in loops loop over all enumerable properties, this means if you add any additional properties to the array's prototype, then those properties will also appear in the loop.
Array.prototype.decimalfy = function() {
for (let i = 0; i < this.length; i++) {
this[i] = this[i].toFixed(2);
}
};
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (const index in digits) {
console.log(digits[index]);
}
Prints:
0
1
2
3
4
5
6
7
8
9
function() {
 for (let i = 0; i < this.length; i++) {
  this[i] = this[i].toFixed(2);
 }
}
This is why for...in loops are discouraged when looping over arrays.
NOTE: The forEach loop is another type of for loop in JavaScript.
However, forEach() is actually an array method, so it can only be used
exclusively with arrays. There is also no way to stop or break a
forEach loop. If you need that type of behavior in your loop, you’ll
have to use a basic for loop.
For...of loop
The for...of loop is used to loop over any type of data that is iterable.
Example:
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (const digit of digits) {
console.log(digit);
}
Prints:
0
1
2
3
4
5
6
7
8
9
This makes the for...of loop the most concise version of all the for loops.
But wait, there’s more! The for...of loop also has some additional benefits that fix the weaknesses of the for and for...in loops.
You can stop or break a for...of loop at anytime.
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (const digit of digits) {
if (digit % 2 === 0) {
continue;
}
console.log(digit);
}
Prints:
1
3
5
7
9
And you don’t have to worry about adding new properties to objects. The for...of loop will only loop over the values in the object.
Here is a useful mnemonic for remembering the difference between for...in Loop and for...of Loop.
"index in, object of"
for...in Loop => iterates over the index in the array.
for...of Loop => iterates over the object of objects.
for of is used to iterate over iterables and for in is used to iterate over object properties
Here's a trick to remember:
for of is not for objects (so it's for iterables)
for in is not for iterables (so it's for objects)
Another trick:
for in returns object indices (keys) while for of returns values
//for in, iterates keys in an object and indexes in an array
let obj={a:1, b:2}
for( const key in obj)
console.log(obj[key]); //would print 1 and 2
console.log(key); //would print a and b
let arr = [10, 11, 12, 13];
for (const item in arr)
console.log(item); //would print 0 1 2 3
//for of, iterates values in an array or any iterable
let arr = [10, 11, 12, 13];
for (const item of arr )
console.log(item); //would print 10 11 12 13
Another difference between the two loops, which nobody has mentioned before:
Destructuring for...in is deprecated. Use for...of instead.
Source
So if we want to use destructuring in a loop, for get both index and value of each array element, we should to use the for...of loop with the Array method entries():
for (const [idx, el] of arr.entries()) {
console.log( idx + ': ' + el );
}
The for...in statement iterates over the enumerable properties of an object, in an arbitrary order.
Enumerable properties are those properties whose internal [[Enumerable]] flag is set to true, hence if there is any enumerable property in the prototype chain, the for...in loop will iterate on those as well.
The for...of statement iterates over data that iterable object defines to be iterated over.
Example:
Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};
let iterable = [3, 5, 7];
for (let i in iterable) {
console.log(i); // logs: 0, 1, 2, "arrCustom", "objCustom"
}
for (let i in iterable) {
if (iterable.hasOwnProperty(i)) {
console.log(i); // logs: 0, 1, 2,
}
}
for (let i of iterable) {
console.log(i); // logs: 3, 5, 7
}
Like earlier, you can skip adding hasOwnProperty in for...of loops.
Short answer: for...in loops over keys, while for...of loops over values.
for (let x in ['a', 'b', 'c', 'd'] {
console.log(x);
}
// Output
0
1
2
3
for (let x of ['a', 'b', 'c', 'd'] {
console.log(x);
}
// Output
a
b
c
d
The for-in statement iterates over the enumerable properties of an object, in arbitrary order.
The loop will iterate over all enumerable properties of the object itself and those the object inherits from its constructor's prototype
You can think of it as "for in" basically iterates and list out all the keys.
var str = 'abc';
var arrForOf = [];
var arrForIn = [];
for(value of str){
arrForOf.push(value);
}
for(value in str){
arrForIn.push(value);
}
console.log(arrForOf);
// ["a", "b", "c"]
console.log(arrForIn);
// ["0", "1", "2", "formatUnicorn", "truncate", "splitOnLast", "contains"]
There are some already defined data types which allows us to iterate over them easily e.g Array, Map, String Objects
Normal for in iterates over the iterator and in response provides us with the keys that are in the order of insertion as shown in below example.
const numbers = [1,2,3,4,5];
for(let number in number) {
console.log(number);
}
// result: 0, 1, 2, 3, 4
Now if we try same with for of, then in response it provides us with the values not the keys. e.g
const numbers = [1,2,3,4,5];
for(let numbers of numbers) {
console.log(number);
}
// result: 1, 2, 3, 4, 5
So looking at both of the iterators we can easily differentiate the difference between both of them.
Note:- For of only works with the Symbol.iterator
So if we try to iterate over normal object, then it will give us an error e.g-
const Room = {
area: 1000,
height: 7,
floor: 2
}
for(let prop in Room) {
console.log(prop);
}
// Result area, height, floor
for(let prop of Room) {
console.log(prop);
}
Room is not iterable
Now for iterating over we need to define an ES6 Symbol.iterator e.g
const Room= {
area: 1000, height: 7, floor: 2,
[Symbol.iterator]: function* (){
yield this.area;
yield this.height;
yield this.floors;
}
}
for(let prop of Room) {
console.log(prop);
}
//Result 1000, 7, 2
This is the difference between For in and For of. Hope that it might clear the difference.
The for-in loop
for-in loop is used to traverse through enumerable properties of a collection, in an arbitrary order. A collection is a container type object whose items can be using an index or a key.
var myObject = {a: 1, b: 2, c: 3};
var myArray = [1, 2, 3];
var myString = "123";
console.log( myObject[ 'a' ], myArray[ 1 ], myString[ 2 ] );
for-in loop extracts the enumerable properties (keys) of a collection all at once and iterates over it one at a time. An enumerable property is the property of a collection that can appear in for-in loop.
By default, all properties of an Array and Object appear in for-in loop. However, we can use Object.defineProperty method to manually configure the properties of a collection.
var myObject = {a: 1, b: 2, c: 3};
var myArray = [1, 2, 3];
Object.defineProperty( myObject, 'd', { value: 4, enumerable: false } );
Object.defineProperty( myArray, 3, { value: 4, enumerable: false } );
for( var i in myObject ){ console.log( 'myObject:i =>', i ); }
for( var i in myArray ){ console.log( 'myArray:i =>', i ); }
In the above example, the property d of the myObject and the index 3 of myArray does not appear in for-in loop because they are configured with enumerable: false.
There are few issues with for-in loops. In the case of Arrays, for-in loop will also consider methods added on the array using myArray.someMethod = f syntax, however, myArray.length remains 4.
The for-of loop
It is a misconception that for-of loop iterate over the values of a collection. for-of loop iterates over an Iterable object. An iterable is an object that has the method with the name Symbol.iterator directly on it one on one of its prototypes.
Symbol.iterator method should return an Iterator. An iterator is an object which has a next method. This method when called return value and done properties.
When we iterate an iterable object using for-of loop, the Symbol.iterator the method will be called once get an iterator object. For every iteration of for-of loop, next method of this iterator object will be called until done returned by the next() call returns false. The value received by the for-of loop for every iteration if the value property returned by the next() call.
var myObject = { a: 1, b: 2, c: 3, d: 4 };
// make `myObject` iterable by adding `Symbol.iterator` function directlty on it
myObject[ Symbol.iterator ] = function(){
console.log( `LOG: called 'Symbol.iterator' method` );
var _myObject = this; // `this` points to `myObject`
// return an iterator object
return {
keys: Object.keys( _myObject ),
current: 0,
next: function() {
console.log( `LOG: called 'next' method: index ${ this.current }` );
if( this.current === this.keys.length ){
return { done: true, value: null }; // Here, `value` is ignored by `for-of` loop
} else {
return { done: false, value: _myObject[ this.keys[ this.current++ ] ] };
}
}
};
}
// use `for-of` loop on `myObject` iterable
for( let value of myObject ) {
console.log( 'myObject: value => ', value );
}
The for-of loop is new in ES6 and so are the Iterable and Iterables. The Array constructor type has Symbol.iterator method on its prototype. The Object constructor sadly doesn't have it but Object.keys(), Object.values() and Object.entries() methods return an iterable (you can use console.dir(obj) to check prototype methods). The benefit of the for-of loop is that any object can be made iterable, even your custom Dog and Animal classes.
The easy way to make an object iterable is by implementing ES6 Generator instead of custom iterator implementation.
Unlike for-in, for-of loop can wait for an async task to complete in each iteration. This is achieved using await keyword after for statement documentation.
Another great thing about for-of loop is that it has Unicode support. According to ES6 specifications, strings are stored with UTF-16 encoding. Hence, each character can take either 16-bit or 32-bit. Traditionally, strings were stored with UCS-2 encoding which has supports for characters that can be stored within 16 bits only.
Hence, String.length returns number of 16-bit blocks in a string. Modern characters like an Emoji character takes 32 bits. Hence, this character would return length of 2. for-in loop iterates over 16-bit blocks and returns the wrong index. However, for-of loop iterates over the individual character based on UTF-16 specifications.
var emoji = "😊🤣";
console.log( 'emoji.length', emoji.length );
for( var index in emoji ){ console.log( 'for-in: emoji.character', emoji[index] ); }
for( var character of emoji ){ console.log( 'for-of: emoji.character', character ); }
for...of loop works only with iterable objects. In JavaScript, iterables are objects which can be looped over.
String, Array, TypedArray, Map, and Set are all built-in iterables, because each of their prototype objects implements an ##iterator method. So, for...of loop works on the mentioned object types.
Object in JavaScript is not iterable by default. So, for...of loop does not work on objects.
In simple words, for...of works with strings and arrays but not with objects.
for...in works with those properties whose enumerable flag is set to true.
Enumerable flag for properties created via simple assignment or property initializer are by default true.
Enumerable flag for properties created via Object.defineProperty are by default false.
Here is a more detailed post with examples: https://dev.to/swastikyadav/difference-between-forof-and-forin-loop-in-javascript-j2o
A see a lot of good answers, but I decide to put my 5 cents just to have good example:
For in loop
iterates over all enumerable props
let nodes = document.documentElement.childNodes;
for (var key in nodes) {
console.log( key );
}
For of loop
iterates over all iterable values
let nodes = document.documentElement.childNodes;
for (var node of nodes) {
console.log( node.toString() );
}
When I first started out learning the for in and of loop, I was confused with my output too, but with a couple of research and understanding you can think of the individual loop like the following :
The
for...in loop returns the indexes of the individual property and has no effect of impact on the property's value, it loops and returns information on the property and not the value.
E.g
let profile = {
name : "Naphtali",
age : 24,
favCar : "Mustang",
favDrink : "Baileys"
}
The above code is just creating an object called profile, we'll use it for both our examples, so, don't be confused when you see the profile object on an example, just know it was created.
So now let us use the for...in loop below
for(let myIndex in profile){
console.log(`The index of my object property is ${myIndex}`)
}
// Outputs :
The index of my object property is 0
The index of my object property is 1
The index of my object property is 2
The index of my object property is 3
Now Reason for the output being that we have Four(4) properties in our profile object and indexing as we all know starts from 0...n, so, we get the index of properties 0,1,2,3 since we are working with the for..in loop.
for...of loop* can return either the property, value or both, Let's take a look at how.
In javaScript, we can't loop through objects normally as we would on arrays, so, there are a few elements we can use to access either of our choices from an object.
Object.keys(object-name-goes-here) >>> Returns the keys or properties of an object.
Object.values(object-name-goes-here) >>> Returns the values of an object.
Object.entries(object-name-goes-here) >>> Returns both the keys and values of an object.
Below are examples of their usage, pay attention to Object.entries() :
Step One: Convert the object to get either its key, value, or both.
Step Two: loop through.
// Getting the keys/property
Step One: let myKeys = ***Object.keys(profile)***
Step Two: for(let keys of myKeys){
console.log(`The key of my object property is ${keys}`)
}
// Getting the values of the property
Step One: let myValues = ***Object.values(profile)***
Step Two : for(let values of myValues){
console.log(`The value of my object property is ${values}`)
}
When using Object.entries() have it that you are calling two entries on the object, i.e the keys and values. You can call both by either of the entry. Example Below.
Step One: Convert the object to entries, using ***Object.entries(object-name)***
Step Two: **Destructure** the ***entries object which carries the keys and values***
like so **[keys, values]**, by so doing, you have access to either or both content.
// Getting the keys/property
Step One: let myKeysEntry = ***Object.entries(profile)***
Step Two: for(let [keys, values] of myKeysEntry){
console.log(`The key of my object property is ${keys}`)
}
// Getting the values of the property
Step One: let myValuesEntry = ***Object.entries(profile)***
Step Two : for(let [keys, values] of myValuesEntry){
console.log(`The value of my object property is ${values}`)
}
// Getting both keys and values
Step One: let myBothEntry = ***Object.entries(profile)***
Step Two : for(let [keys, values] of myBothEntry){
console.log(`The keys of my object is ${keys} and its value
is ${values}`)
}
Make comments on unclear parts section(s).
Everybody did explain why this problem occurs, but it's still very easy to forget about it and then scratching your head why you got wrong results. Especially when you're working on big sets of data when the results seem to be fine at first glance.
Using Object.entries you ensure to go trough all properties:
var arr = [3, 5, 7];
arr.foo = "hello";
for ( var [key, val] of Object.entries( arr ) ) {
console.log( val );
}
/* Result:
3
5
7
hello
*/
In simple terms forIN iterates over the KEYS IN the array(index)/object(key),
whereas forOF iterates over the VALUES OF the array(value).

Javascript Arrays - Find Duplicates [duplicate]

This question already has answers here:
Get all non-unique values (i.e.: duplicate/more than one occurrence) in an array
(97 answers)
Closed 8 years ago.
Here is my question...
Given an array populated with numbers as a function parameter, produce a resulting array which contains any duplicates number from the array.
For example, given the array [ 1, 2, 4, 4, 3, 3, 1, 5, 3 ] it should return [1, 4, 3]. For extra bonus points return a sorted array.
I am starting out with Javascript - I know the language however, using it in the correct way ( as one should ) I'm still getting to grips with.
My pseudo code for this would be to:
Create an array with the numbers above var numbers = [1, 2, 4, 4, 3, 3, 1, 5, 3];
Then create an empty array named "result" var result = [];
Create a for loop that goes through the var numbers to check for duplicates which will then populate the empty array "result" with the duplicates
for (var i = 0;i < numbers.length; i++) {
//This is where I'm stuck...
}
I'm not sure what to do within the for loop to populate the var result and to throw in to the mix... The given array has to be a function parameter which makes sense so you can change the numbers in one place.
Any feedback on my thought process on this so far is greatly appreciated but ultimately I am wanting to learn how to achieve this.
Here is a JSFiddle of my progress so far... http://jsfiddle.net/fbauW/
One way of doing this (and it's not the only way) is by checking for existing elements in the array. Take a look at JavaScript's lastIndexOf function:
http://www.w3schools.com/jsref/jsref_lastindexof_array.asp
It will return -1 if the object does not exist in your array, and if it exists, will return an index of a later position than you are in. So you can use an if statement in your loop that checks whether or not there is another index containing your number, and add it in to your results array IF AND ONLY IF the index you get back != the index you are currently on (if they equal, this means that there is only one of that element in the list).
If you need more help, comment here and I can type some code in!
Good luck!
Array.prototype.contains = function(k) {
for ( var p in this)
if (this[p] === k)
return true;
return false;
};
//this prototype function checks if an element is already in the array or not
//go through all the array and push the element to result if it is not
//this way we can eliminate duplicates
//result will contain the resultant array
function findDuplicates(Numbers) {
var arrayLength = Numbers.length, i, j, result = [];
for (i = 0; i < arrayLength; i++) {
for (j = 0; j < arrayLength; j++) {
if (a[i] == a[j] && i != j && !result.contains(a[i])) {
result.push(a[i]);
}
}
}
return result;
}

Categories

Resources