for in and for of loops - javascript

2 quick questions
How do I access the index position in an array using for...of?
How do I access the value in an array using for...in?
Pseudo code
var arr = [3, 5, 7];
var pos, value;
for (pos in arr) {
console.log(pos); // logs "0", "1", "2"
}
for (value of arr) {
console.log(value); // logs "3", "5", "7"
}

There is a way:
for (let [key, value] of arr.entries()) {
// ...
}
It uses the Array.prototype.entries() which returns an iterator over tuples of (key; value) and array destructuring that turns it into 2 separated variables.
And to address your answer in particular: when you iterate over arrays you should use either for (var i = 0; i < arr.length; ++i) or for-of, but not for-in.

You can get the value in for in simply by using the index on the original array:
var arr = [3, 5, 7];
var pos, value;
for (pos in arr) {
console.log(arr[pos]); // logs 3, 5, 7
}
Note that using for...in to iterate arrays is a bad practice.
Getting the index in for…of requires an external counter:
var arr = [3, 5, 7];
var pos = 0, value;
for (value of arr) {
console.log(pos++); // logs 0, 1, 2
}
A better solution for both cases would be Array.prototype.forEach:
arr.forEach((value, index) => {
console.log('index: ', index);
console.log('value: ', value);
});

Using for...in
for (pos in arr) {
console.log(arr[pos]);// logs "3", "5", "7"
}
There is no way using for...of. This will give you an idea.
var arr = ["3", 3, {}, true];
for (value of arr) {
console.log(typeof value);
}

Related

Get data from each array of array with sequence output

i am trying to get sequence index of each array of array like I have an element of the array and that 5 arrays have multiple elements and I want to get the first index of each array then the second and so.
below is my array data
const arrData = [[1,2,4,6],[3,8,7],[12,13],[],[9,10]];
and my expected outout [1,3,12,9,2,8,13,10,4,7,6]
give me some sort of solution to fix my issue
Following might work:
const src = [[1,2,4,6],[3,8,7],[12,13],[],[9,10]],
pickByOne = arr => {
const result = [],
{length} = arr.flat()
while(result.length < length){
for(a of arr){
a.length && result.push(a.shift())
}
}
return result
}
console.log(pickByOne(src))
You can also use zip from lodash. Since the function takes a sequence of arguments and you have an array, you'll need to spread the array with ...
const _ = require("lodash");
const arrData = [[1,2,4,6],[3,8,7],[12,13],[],[9,10]];
const z = _.zip(...arrData)
This will give you the following result:
[
[ 1, 3, 12, undefined, 9 ],
[ 2, 8, 13, undefined, 10 ],
[ 4, 7, undefined, undefined, undefined ],
[ 6, undefined, undefined, undefined, undefined ]
]
You can already see it's in the order that you want. Now to clean things up. You can use flatMap in its simplest form to flatten the array.
// lodash
const fm = _.flatMap(z)
// or with Array.prototype.flat()
const fm = z.flat()
This will give you a single array.
[
1, 3, 12,
undefined, 9, 2,
8, 13, undefined,
10, 4, 7,
undefined, undefined, undefined,
6, undefined, undefined,
undefined, undefined
]
Now you just need to remove all the undefined elements by filtering (keeping) all the elements that are not undefined.
// lodash
_.filter(fm, _.negate(_.isUndefined))
and you have your final result.
[1, 3, 12, 9, 2, 8, 13, 10, 4, 7, 6]
There are many ways to solve this issue so you'll need to decide based on your particular case and balance simplicity, code legibility, efficiency, etc.
Find the longest length of the sub-array using Array.map() to get the length of all sub-arrays, and Math.max(). Use Array.from() to create an array with the length of the longest length. For each index in the created array, use Array.flatMap() to get all items from the original sub-arrays. If the item is undefined, use the Nullish coalescing operator (??) to substitute it with an empty array, which Array.flatMap() would ignore when flattening the resulting array. Flatten the output of Array.from() using Array.flat() to get a single array.
const fn = arr =>
Array.from({ length: Math.max(...arr.map(o => o.length)) }, (_, i) =>
arr.flatMap(o => o[i] ?? [])
).flat();
const arrData = [[1,2,4,6],[3,8,7],[12,13],[],[9,10]];
const result = fn(arrData);
console.log(result);
Please try my below solution may be it will fix your
let data = [[], [], [1, 2, 4, 6], [8, 9, 10], [], [12], [14, 15], []], index = 0;
data = data.filter(o => o.length != 0)
const result = [];
for (i = 0; i < data.length; i++) {
if (data[i].length > index) {
index = data[i].length
}
if (data[i].length > 0) {
for (j = 0; j < index; j++) {
if (data[j][i] != undefined) {
result.push(data[j][i]);
}
}
}
}
console.log("Result", result);
Since it's a nested array, you can loop through and check if the first element of each nested array is undefined or not. If no, you can push it into the result array. I wrote the function for your ref. Please check
const arrData = [[1, 2, 4, 6], [3, 8, 7], [12, 13], [], [9, 10]];
function sorter(arr) {
var result = [];
if (arr.length > 0) {
for (var i = 0; i < arr.length; i++) {
if (arr[i].length > 0) {
if (arr[i][0] !== undefined) {
result.push(arr[i][0]);
}
}
}
}
return result;
}
console.log(sorter(arrData));
I hope this is what you expected! Please reach me if you need clarification.
You need to keep track of the index which defines the position of the elements to get in each iteration.
Use a while loop that would terminate when there are no remaining elements in any of the arrays at a certain index.
Use .map to get a list of elements in each array at the index
Remove undefined elements in this list using .filter in case one of the arrays has no element at an index
Use .isEmpty to check if this list is empty, then, terminate
const arrData = [[1,2,4,6],[3,8,7],[12,13],[],[9,10]];
let res = [], index = 0;
while(true) {
const elementsAtIndex = _.filter(
_.map(arrData, e => e[index]),
e => e!==undefined
);
if(_.isEmpty(elementsAtIndex)) break;
res = [...res, ...elementsAtIndex];
index++;
}
console.log(...res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"></script>
Simple one without any operator whould look like....
const ipArr = [ [1, 2, 4, 6], [8, 9, 10], [], [12], [14, 15], [] ]
let maxLength = 0
for (let i = 0; i < ipArr.length; i++) {
if (ipArr[i].length > maxLength) maxLength = ipArr[i].length
}
const opArr = []
for (let j = 0; j < maxLength; j++) {
for (let k = 0; k < ipArr.length; k++) {
if (ipArr[k][j]) opArr.push(ipArr[k][j])
}
}
console.log('opArr = ', opArr)

Return array of strings and numbers from parsed object

Trying to create a function to remove duplicates from an array of strings, numbers, and booleans by adding array values to an object as the keys and then pushing the keys to a result array. I know I can write it much more quickly and cleanly with a callback and ".filer" / ".indexOf" but I'm trying to write it without.
const removeDuplicates = (arr) => {
let result = [];
let obj = {};
for(let i = 0; i < arr.length; i++) {
obj[arr[i]] = "";
}
for(key in obj) {
if(typeof key === 'number'){
result.push(parseInt(key));
}else{
result.push(key);
}
}
return result;
}
const myArr = [1,2,2,"hello","hello",3,3,"goodbye","goodbye",4,4,4,true,true,5,5];
console.log(removeDuplicates(myArr));
This function returns:
["1", "2", "3", "4", "5", "hello", "goodbye", "true"]
I am expecting:
[1, 2, 3, 4, 5, "hello", "goodbye", "true"];
Not sure why my "parseInt" isn't working. I suspect it has something to do with how I'm using "typeOf". Or possibly when I'm adding array values to the object they are being saved in the object keys as strings. Any help is appreciated.
const myArr = [1,2,2,"hello","hello",3,3,"goodbye","goodbye",4,4,4,true,true,5,5];
let obj = {}
const newArr = myArr.reduce((arr, item) => {
if(!object.hasOwnProperty(item)){
object[item] = 0;
arr.push(item);
}
return arr;
}, []);
console.log(newArr) //[1, 2, "hello", 3, "goodbye", 4, true, 5];
If the order matters you can do return arr.sort()
First of all your this condition if(typeof key === 'number') is never satisfied, they are all of type string.
Second, instead of writing this whole block
for(key in obj) {
if(typeof key === 'number'){
result.push(parseInt(key));
}else{
result.push(key);
}
}
return result;
You can just return Object.keys(obj).
Now where ever you want to check for string vs number just do (+index).toString() === index)
It works properly:
const removeDuplicates = (arr) => {
let result = [];
let s = new Set()
for (key in arr)
{
if (!s.has(arr[key])) {
result.push(arr[key])
s.add(arr[key])
}
}
return result;
}
You check the key of an object, this is always a string, the check does not work, but you could convert the value to a number and back to a string and check it with the key. If true, you have a numerical value.
const removeDuplicates = (arr) => {
let result = [];
let obj = {};
for (let i = 0; i < arr.length; i++) {
obj[arr[i]] = "";
}
for (key in obj) {
if ((+key).toString() === key) {
result.push(+key);
} else {
result.push(key);
}
}
return result;
}
const myArr = [1, 2, 2, "hello", "hello", 3, 3, "goodbye", "goodbye", 4, 4, 4, true, true, 5, 5];
console.log(removeDuplicates(myArr));
Just for the records, you could use a Set, which gives unique results.
const
array = [1, 2, 2, "hello", "hello", 3, 3, "goodbye", "goodbye", 4, 4, 4, true, true, 5, 5],
unique = [...new Set(array)];
console.log(unique); // in order of appearance
You can use JavaScript built in object Set to keep unique values of any type.
Here is how code looks.
function removeDuplicates(arr){
let result = Array.from(new Set(arr))
return result;
}
const arr = [1,2,2,"hello","hello",3,3,"goodbye","goodbye",4,4,4,true,true,5,5];
console.log(removeDuplicates(arr));
This will give you your expected result.
Let me know if it worked or not. :)
const removeDuplicates = (arr) => {
let result = [];
let obj = {};
for(let i = 0; i < arr.length; i++) {
obj[arr[i]] = "";
}
for(key in obj) {
if(isNaN(+key)){
result.push(key);
}else{
result.push(+key);
}
}
return result;
}
const myArr = [1,2,2,"hello","hello",3,3,"goodbye","goodbye",4,4,4,true,true,5,5];
console.log(removeDuplicates(myArr));
typeOf "2" will return string not a number thats why your code is not working.You need to try to parse it into int and then decide.
Hope this helps!!!

Take highest property value and return it in an array in Javascript

I want to loop through this object and return the keys with the highest property values into an array.
Object {clear-spring: 3, deep-autumn: 2, warm-spring: 1, light-summer: 2, light-spring: 2, clear-summer: 3}
In this case, I want an array like this:
["clear-summer", "clear-spring"]
Is there an efficient way to do this with jQuery or pure javascript?
You simply need to iterate over your item once, keeping track of what ever the largest set is that you've found so far.
var a = {'clear-spring': 3, 'deep-autumn': 2, 'warm-spring': 1, 'light-summer': 2, 'light-spring': 2, 'clear-summer': 3};
var max = {
val: Number.NEGATIVE_INFINITY,
keys: []
}
for (var prop in a) {
if (a.hasOwnProperty(prop)) {
var n = a[prop];
if (n >= max.val) {
if (n > max.val) {
max.keys = [];
}
max.val = n;
max.keys.push(prop);
}
}
}
You may use for.. in to loop through the object
var object = {clear-spring: 3, deep-autumn: 2, warm-spring: 1, light-summer: 2, light-spring: 2, clear-summer: 3};
// Iterates over the oject
for (var key in object) {
if(object.hasOwnProperty(key)) {
// Key === 'clear-spring' (sample)
// object[key] === 3 (sample)
// do whatever you want
}
}
var o = {'clear-spring': 3, 'deep-autumn': 2, 'warm-spring': 1, 'light-summer': 2, 'light-spring': 2, 'clear-summer': 3};
var max = 0, result = [];
// find max:
for(var k in o) { if (o[k] > max) max = o[k] }
// find keys matching the max:
for(var k in o) { if (o[k] === max) result.push(k) }
// log result
console.log(result);
Not sure if most efficient, but first find the max value, then go back and pull out all the ones that match max value.
var obj = {'clear-spring': 3, 'deep-autumn': 2, 'warm-spring': 1, 'light-summer': 2, 'light-spring': 2, 'clear-summer': 3};
var ary = [];
var max = Number.NEGATIVE_INFINITY;
for (var prop in obj) {
if (obj[prop] > max) {
max = obj[prop];
}
}
for (var prop in obj) {
if (obj[prop] === max) {
ary.push(prop);
}
}

Is element in array js

Following an old question, I still have a problem:
a = ["apple", "banana", "orange", "apple"];
a.indexOf("apple") = 0
What is the easiest way to find BOTH indexes of "apple" element in array? I want to delete them both at once - is it possible?
That's the task for filter method:
var noApples = a.filter(function(el) { return el != "apple"; })
What is the easiest way to find BOTH indexes of "apple" element in array?
You asked that, but also asked about deleting. I'll tackle indexes first, then deletion.
Indexes:
There's no shortcut, you have to loop through it. You can use a simple for loop:
var indexes = [];
var index;
for (index = 0; index < a.length; ++index) {
if (a[n] === "apple") {
indexes.push(index);
}
});
Or two ES5 options: forEach:
var indexes = [];
a.forEach(function(entry, index) {
if (entry === "apple") {
indexes.push(index);
}
});
Or reduce:
var indexes = a.reduce(function(acc, entry, index) {
if (entry === "apple") {
acc.push(index);
}
return acc;
}, []);
...although frankly that does't really buy you anything over forEach.
Deletion:
From the end of your question:
I want to delete them both at once - is it possible?
Sort of. In ES5, there's a filter function you can use, but it creates a new array.
var newa = a.filter(function(entry) {
return entry !== "apple";
});
That basically does this (in general terms):
var newa = [];
var index;
for (index = 0; index < a.length; ++index) {
if (a[n] !== "apple") {
newa.push(index);
}
});
Array.indexOf takes a second, optional argument: the index to start from. You can use this inside a loop to specify to start from the last one.
var indices = [],
index = 0;
while (true) {
index = a.indexOf("apple", index);
if (index < 0) {
break;
}
indices.push(index);
}
Once indexOf returns -1, which signals "no element found", the loop will break.
The indices array will then hold the correct indices.
There is an example on the Mozilla page on indexOf which has some equivalent code. I'm not so much of a fan because of the increased duplication, but it is shorter, which is nice.
A for loop will do the trick. Or use forEach as T.J. Crowder suggests in his elegant answer.
I combined both an example of how to get appleIndexes and also how to "delete" them from the original array by virtue of creating a new array with all but apples in it. This is using oldSchool JavaScript :)
a = ["apple", "banana", "orange", "apple"];
appleIndexes = [];
arrayOfNotApples = [];
for (var i = 0; i < a.length; i++)
{
if (a[i] == "apple")
{
appleIndexes.push(i);
} else {
arrayOfNotApples.push(a[i]);
}
}
If you need to remove elements from an array instance without generating a new array, Array.prototype.splice is a good choice:
var a,
i;
a = ["apple", "banana", "orange", "apple"];
for (i = a.indexOf('apple'); i > -1; i = a.indexOf('apple')) {
a.splice(i, 1);
}
If you can use a new array instance, then Array.prototype.filter is a better choice:
var a,
b;
a = ["apple", "banana", "orange", "apple"];
b = a.filter(function (item, index, array) {
return item !== 'apple';
});
Use the start parameter in array.indexOf(element, start), as described in http://www.w3schools.com/jsref/jsref_indexof_array.asp.
Example:
var a = [1, 3, 4, 1];
var searchElement = 1;
var foundIndices = [];
var startIndex = 0;
while ((index = a.indexOf(searchElement, startIndex)) != -1) {
foundIndices.push(index);
startIndex = index + 1;
}
console.log(foundIndices); // Outputs [0, 3];
A good old while loop :
var i = a.length;
while (i--) {
if (a[i] === 'apple') {
a.splice(i, 1);
}
}
Inside a function :
function removeAll(value, array) {
var i = array.length;
while (i--) {
if (array[i] === value) {
array.splice(i, 1);
}
}
return array;
}
Usage :
removeAll('apple', a);
A couple of recursive solutions.
Javascript
function indexesOf(array, searchElement, fromIndex) {
var result = [],
index = array.indexOf(searchElement, fromIndex >>> 0);
if (index === -1) {
return result;
}
return result.concat(index, indexesOf(array, searchElement, index + 1));
}
function removeFrom(array, searchElement, fromIndex) {
var index = array.indexOf(searchElement, fromIndex >>> 0);
if (index !== -1) {
array.splice(index, 1);
removeFrom(array, searchElement, index);
}
return array;
}
var a = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0];
console.log(indexesOf(a, 0));
console.log(removeFrom(a, 0));
Output
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
On jsFiddle
The fastest, most compatible, route would be to walk the array backwards in a for loop.
for (var a = array.length;a--;)
if (array[a] == 'apple') array.splice(a,1);
if you want to remove all occurrences, you could also use Array.splice recursively
function remove(list, item) {
if(list.indexOf(item)<0)
return list;
list.splice(list.indexOf(item),1);
return list;
}

Javascript, repeating an object key N-times, being N its value

I was wondering how to do this in the more cleaner and optimal way:
I have an Object with the following structure:
{
"125": 2,
"439": 3,
"560": 1,
"999": 2,
...
}
I want to create a flat array repeating every key, the number of times indicated by its value. And bonus points for converting keys (strings) to integers. In this example, the resulting array should be:
[ 125, 125, 439, 439, 439, 560, 999, 999 ]
I've tried several ways but they all look over-engineered. For sure there is an easier way.
This is what I've got with underscore (and it returns an Array of strings, nor integers):
_.compact(_.flatten(_.map(files, function(num, id) {
return new Array(num+1).join('$'+id).split('$')
})))
I know there are plenty of ways to accomplish this. I just only want a clean and quick way. Being a Ruby developer it could be as easy as:
> files = {"125" => 2, "439" => 3, "560" => 1, "999" => 2}
=> {"125"=>2, "439"=>3, "560"=>1, "999"=>2}
> files.map {|key, value| [key.to_i] * value}.flatten
=> [125, 125, 439, 439, 439, 560, 999, 999]
Thanks in advance.
Try this:
var obj = {
"125": 2,
"439": 3,
"560": 1,
"999": 2
}
var arr = [];
for (prop in obj) {
for (var i = 0; i < obj[prop]; i++)
arr.push(parseInt(prop));
}
console.log(arr)
I know this is plain JavaScript but seems cleaner to me than the code you posted:
var dict = {
"125": 2,
"439": 3,
"560": 1,
"999": 2
}
var result = [];
for(key in dict)
for(i = 0; i < dict[key]; i++)
result.push(key * 1);
alert(result);
Hmm... not sure if I got at, but maybe something like this:
var myObj = {
"125": 2,
"439": 3,
"560": 1,
"999": 2
},
myArray = [];
for(k in myObj){
for(i = 0; i < myObj[k]; i++){
myArray.push(k);
}
}
console.log(myArray)
The problem with the other answers above is that the for..in language construct in javascript is going to involve all keys from the objects prototype chain. In this case, we should check and add only the correct keys.
var obj= {
"125": 2,
"439": 3,
"560": 1,
"999": 2
}
var arr=[];
for (var item in map) {
//important check!
if (map.hasOwnProperty(item)) {
arr.push(item);
}
}
Also see: http://www.yuiblog.com/blog/2006/09/26/for-in-intrigue/
Whether any of these approaches is cleaner is quite subjective:
// some helper function for creating an array with repeated values
function repeat(val, times) {
var arr = [];
for(var i = 0; i < times; i = arr.push(val));
return arr;
}
function convert(obj) {
var result = [], key;
for(key in obj) {
result = result.concat(repeat(+key, obj[key]));
}
return result;
}
Or a more functional approach:
Object.keys(obj).reduce(function(result, key) {
return result.concat(repeat(+key, obj[key]));
}, []);
// with underscore.js
_.reduce(_.keys(obj), function(result, key) {
return result.concat(repeat(+key, obj[key]));
}, []);
A helper function:
function flatten(obj){
//static Array method: create array (a elements, value b)
Array.aXb = Array.aXb || function(a,b){
b = b || 0;
return String(this(a)).split(',').map(function(){return b;});
}
//obj2array
var arr = [];
for (var k in obj)
if (+obj[k]) arr = arr.concat(Array.aXb(+obj[k],k));
return arr;
}
var obj= {"125": 2,"439": 3,
"560": 1,"999": 2 },
flatten(obj); //=> [125,125,439,439,439,560,999,999]

Categories

Resources