Populating an array using a for loop and another array - javascript

This is more a learning exercise and nothing super critical - I'm unsure of the best way to Google what I'm looking for, I clicked through a few others suggested answers and didn't find anything that looked super relevant.
I'm wondering if there's a way I can populate an array using another array and a for loop (as opposed to modifying the contents of the existing array in place). What I envision is something like:
var existingArray = ["Thing1", "Thing2", "Thing3"];
let newArray = for (var i=0; i < existingArray.length; i++) {
"Modified string " + existingArray[i];
}
// Output: ["Modified string Thing1", "Modified string Thing2", "Modified string Thing3"]
where I can just create the new array variable and populate it more or less in the same block of code. I know how to do it the maybe more traditional way where I just say:
newArray = [];
oldArray = ["Thing1", "Thing2", "Thing3"]
for (var i = 0; i < oldArray.length; i++) {
newArray.push("Modified string " + oldArray[i]);
}
I'm sorry if this is a somewhat stupid question, I'm just curious if there's a way to do this and if there's any advantage to doing so. It seems like it would be cool to just declare a new array and populate it all with one little chunk of code instead of declaring the new array, then using .push() to populate it.

It would be even better to use .map, since you're transforming one array into another, only one line required:
const existingArray = ["Thing1", "Thing2", "Thing3"];
console.log(
existingArray.map(thing => 'Modified string ' + thing)
);
When you don't have an existing array to .map from, you can still do something similar to create an array immediately by using Array.from - define the length in the first argument, and put the map function in the second argument:
const originalArray = Array.from({ length: 3 }, (_, i) => 'Thing ' + (i + 1));
console.log(originalArray);

newArray = [];
oldArray = ["Thing1", "Thing2", "Thing3"]
for (i in oldArray) {
newArray.push("Modified string " + oldArray[i]);
}
console.log(newArray)

Related

for loop skipping one item in array in javascript

I am trying to make a function that removes strings from an array if they include a character in a certain other list
Here is the code:
var possible = ["salutations", "goodbye", "thanks", "welcome"];
var incorrect = ["o"];
console.log(possible);
function narrowdown(possible, incorrect)
{
var templist = possible;
for (i in possible)
{
console.log(i + " " + possible[i]);
var array1 = possible[i].split("");
var common = array1.filter(value => incorrect.includes(value));
console.log(common)
if (common.length)
{
templist.splice(i, 1);
}
}
possible = templist;
}
narrowdown(possible, incorrect);
console.log(possible);
Here I am trying to remove all the words that include the letter o. I created a temporary array in the function because it has happened to me before that a for loop skips items altogether.
The code first logs the index of the item in the list and then the item itself.
Then it turns the word into an array and checks for overlap between it and the "incorrect" array. It does that correctly and logs the overlapping characters.
The issue seems to be that it skips over the "goodbye" item for some reason. It doesn't even process it.
Here is the output I am getting:
[ 'salutations', 'goodbye', 'thanks', 'welcome' ]
0 salutations
[ 'o' ]
1 thanks
[]
2 welcome
[ 'o' ]
[ 'goodbye', 'thanks' ]
First of all, for (i in possible) is a bad way of looping through an array since it retrieves the keys before the loop begins and it never updates that list of keys. Also, if someone assigns an attribute to the array, like possible.foo = 17, then your loop will also go through that. The issue you're having is that when you splice the array, everything else is shifted one to the left, changing their indices to be one less, so your new index actually skips over the next element. The fix is to use a conventional for loop and decrement i after splicing:
for (let i = 0; i < possible.length; i ++) {
// more code...
if (common.length) {
templist.splice(i, 1);
i --;
}
}
The problem is that the array is re-indexed when you splice. One solution is to iterate in reverse:
var possible = ["salutations", "goodbye", "thanks", "welcome"];
var incorrect = ["o"];
console.log(possible);
function narrowdown(possible, incorrect)
{
var templist = possible;
var i = possible.length;
while (i--)
{
console.log(i + " " + possible[i]);
var array1 = possible[i].split("");
var common = array1.filter(value => incorrect.includes(value));
console.log(common)
if (common.length)
{
templist.splice(i, 1);
}
}
possible = templist;
}
narrowdown(possible, incorrect);
console.log(possible);
The issue comes from the line tempList = possible which is an assignment by reference, meaning that when you do the splice operation you do it on both arrays at the same time.
Generally it is considered bad form to manipulate data like that anyway, you should have narrowDown return a value that you re-assign to possible instead of filtering them in place. If you do that you can also leverage some of the newer array methods:
var possible = ["salutations", "goodbye", "thanks", "welcome"];
var incorrect = ["o"];
function narrowdown(possible, incorrect)
{
return possible.filter(item => !incorrect.some(test => item.includes(test)))
}
possible = narrowdown(possible, incorrect);
console.log(possible);
using the .some will also exit early as soon as there is a match, instead of looping over all incorrect values and the entire string, boosting performance slightly
If you're looking for a less "imperative" version of this function, you can make use of Array.filter(), Array.some(), and String.includes() to make a one-liner function that does the trick (for formatting purposes, I split it in the multiple lines in the snippet below).
const possible = ['salutations', 'goodbye', 'thanks', 'welcome'];
function narrowDown(possible, incorrect) {
return possible.filter((value) => (
!incorrect.some((exclude) => (value.includes(exclude)))
));
}
console.log('["o"]', JSON.stringify(narrowDown(possible, ['o'])));
console.log('["a"]', JSON.stringify(narrowDown(possible, ['a'])));
console.log('["a", "o"]', JSON.stringify(narrowDown(possible, ['a', 'o'])));

How to make strings in an array plural with a for loop?

The goal of the challenge I'm currently working on is to take an array and add an 's' onto the end of each element of it (hopefully pluralizing each word).
Here's what I was able to come up with, but I'm certain that I'm not doing this correctly:
var pets = ['dog', 'cat', 'rat'];
for (pets[i] = pets[i] + 's';);
console.log(pets);
I realize I'm probably not all that close to the answer, but this lesson is throwing in a few tips without explaining how/why they work. The entire line of pets[i] = pets[i] + 's'; was what was suggested by the lesson.
I'm hoping to still be able to solve the answer on my own, so if someone could include an explanation as to why the for loop is structured the way you happen to structure it, that would be fantastic!
Classic use case for Array#map
var pets = ['dog', 'cat', 'rat'];
var pluralVersion = pets.map(function(el) {
return el + 's';
});
console.log(pluralVersion);
But, going with your approach, set the new value for each item in array in a for-loop
var pets = ['dog', 'cat', 'rat'];
for (var i = 0, length = pets.length; i < length; i++) {
pets[i] = pets[i] + 's';
}
console.log(pets);
In modern Javascript that makes the idea of immutability very popular, you don't actually change values inside your original array but instead map a function to these values and receive a new array. It's as easy as
const pets = ['dog', 'cat', 'rat'];
const petsPlural = pets.map(pet => `${pet}s`);
It may overwhelm you so let's deconstruct each part.
First, the map. This is a property of every array and is a function. When you apply it, you supply a single argument which is, again, a function which is applied to every element in original array one by one. As a result, the return value of calling someArray.map is a new array. The coolest thing is that original array (in your case, pets) doesn't get changed. It preserves original values!
Next, the (...) => ... syntax. It is an arrow function which has been introduced in ES6 and is already supported by most modern browser (not Safari). For example,
(arg1, arg2) => arg1 + arg2
is a short notation for
function (arg1, arg2) {
return arg1 + arg2
}
And finally, that backtick thing. It is called template literal. Everything that is enclosed in ${ and } within this string is evaluated while whatever is outside is just places as is. In fact, when you write, say
`${abc}def${123}xyz`
it is equivalent to
abc + 'def' + 123 + 'xyz'
So, in this case,
`${pet}s`
is equivalent to
pet + 's'
You can even see how easy it is now to read this part of the code.
Your for syntax is not correct - it should have three parts, like so:
var pets = ['dog', 'cat', 'rat'];
for (var i = 0; i < pets.length; i++) { //Initialize i as 0. As long as i is less than the length of items in 'pets', continue looping. With each loop, increment i by 1.
pets[i] = pets[i] + 's';
}
console.log(pets);
I assume you are new to JavaScript.
If that is not the case then please forgive my previous statement.
In JavaScript, when you use a + between two string objects, the result is an appended string.
What it means is,
let appendedString = "string1" + "string2" ;
console.log(appendedString)
//output = string1string2
Now, for your example, you were supposed to append an 's' at the end of each string to transform that string into its plural form.
Thus the hint was to iterate over each string using a for loop and append an ''s" to each one of them.
Now, for iteration, my first approach would be to use the map function. But, to be precise it really doesn't matter in this particular exmaple.
Hope, that makes it clear for you.
I loved this question. For this job you don't need any for loop in JS. The is Array.prototype.map(); Let's also handle the irregularities.
var pets = ['dog', 'cat', 'rat', 'deer', 'goose', 'mouse'],
lut = {mouse: "mice", goose: "geese", deer: "deer"},
pluralPets = pets.map(p => lut[p] ? lut[p] : p+"s");
console.log(pluralPets);
If you are using the for loop approach which I believe you are looking for, a better way to write Rayon's answer would be;
var pets = ['cat', 'dog', 'rat'];
var length = pets.length;
for (i = 0; i < length; i++) {
pets[i] = pets[i] + 's';
}
console.log(pets);

JavaScript: Difference between .forEach() and .map()

I know that there were a lot of topics like this. And I know the basics: .forEach() operates on original array and .map() on the new one.
In my case:
function practice (i){
return i+1;
};
var a = [ -1, 0, 1, 2, 3, 4, 5 ];
var b = [ 0 ];
var c = [ 0 ];
console.log(a);
b = a.forEach(practice);
console.log("=====");
console.log(a);
console.log(b);
c = a.map(practice);
console.log("=====");
console.log(a);
console.log(c);
And this is output:
[ -1, 0, 1, 2, 3, 4, 5 ]
=====
[ -1, 0, 1, 2, 3, 4, 5 ]
undefined
=====
[ -1, 0, 1, 2, 3, 4, 5 ]
[ 0, 1, 2, 3, 4, 5, 6 ]
I can't understand why using practice changes value of b to undefined.
I'm sorry if this is silly question, but I'm quite new in this language and answers I found so far didn't satisfy me.
They are not one and the same. Let me explain the difference.
forEach: This iterates over a list and applies some operation with side effects to each list member (example: saving every list item to the database) and does not return anything.
map: This iterates over a list, transforms each member of that list, and returns another list of the same size with the transformed members (example: transforming list of strings to uppercase). It does not mutate the array on which it is called (although the callback function may do so).
References
Array.prototype.forEach() - JavaScript | MDN
Array.prototype.map() - JavaScript | MDN
Array.forEach “executes a provided function once per array element.”
Array.map “creates a new array with the results of calling a provided function on every element in this array.”
So, forEach doesn’t actually return anything. It just calls the function for each array element and then it’s done. So whatever you return within that called function is simply discarded.
On the other hand, map will similarly call the function for each array element but instead of discarding its return value, it will capture it and build a new array of those return values.
This also means that you could use map wherever you are using forEach but you still shouldn’t do that so you don’t collect the return values without any purpose. It’s just more efficient to not collect them if you don’t need them.
forEach()
map()
Functionality
Performs given operation on each element of the array
Performs given "transformation" on a "copy" of each element
Return value
Returns undefined
Returns new array with transformed elements, leaving back original array unchanged.
Preferrable usage scenario and example
Performing non-tranformation like processing on each element. For example, saving all elements in the database.
Obtaining array containing output of some processing done on each element of the array. For example, obtaining array of lengths of each string in the array
forEach() example
chars = ['Hello' , 'world!!!'] ;
var retVal = chars.forEach(function(word){
console.log("Saving to db: " + word)
})
console.log(retVal) //undefined
map() example
chars = ['Hello' , 'world!!!'] ;
var lengths = chars.map(function(word){
return word.length
})
console.log(lengths) //[5,8]
The main difference that you need to know is .map() returns a new array while .forEach() doesn't. That is why you see that difference in the output. .forEach() just operates on every value in the array.
Read up:
Array.prototype.forEach() - JavaScript | MDN
Array.prototype.map() - JavaScript | MDN
You might also want to check out:
- Array.prototype.every() - JavaScript | MDN
Performance Analysis
For loops performs faster than map or foreach as number of elements in a array increases.
let array = [];
for (var i = 0; i < 20000000; i++) {
array.push(i)
}
console.time('map');
array.map(num => {
return num * 4;
});
console.timeEnd('map');
console.time('forEach');
array.forEach((num, index) => {
return array[index] = num * 4;
});
console.timeEnd('forEach');
console.time('for');
for (i = 0; i < array.length; i++) {
array[i] = array[i] * 2;
}
console.timeEnd('for');
forEach: If you want to perform an action on the elements of an Array and it is same as you use for loop. The result of this method does not give us an output buy just loop through the elements.
map: If you want to perform an action on the elements of an array and also you want to store the output of your action into an Array. This is similar to for loop within a function that returns the result after each iteration.
Hope this helps.
map returns a new array.
forEach has no return value.
That's the heart of the difference. Most of the other answers here say effectively that, but in a much more convoluted way.
forEach() :
return value : undefined
originalArray : not modified after the method call
newArray is not created after the end of method call.
map() :
return value : new Array populated with the results of calling a provided function on every element in the calling array
originalArray : not modified after the method call
newArray is created after the end of method call.
Conclusion:
Since map builds a new array, using it when you aren't using the returned array is an anti-pattern; use forEach or for-of instead.
The difference lies in what they return. After execution:
arr.map()
returns an array of elements resulting from the processed function; while:
arr.forEach()
returns undefined.
one of the shuttle difference not mentioned here is that forEach() can loop over static (not live) NodeList while map() cannot
//works perfectly
document.querySelectorAll('.score').forEach(element=>console.log(element));
//Uncaught TypeError: document.querySelectorAll(...).map is not a function
document.querySelectorAll('.score').map(element=>console.log(element));
Diffrence between Foreach & map :
Map() : If you use map then map can return new array by iterating main array.
Foreach() : If you use Foreach then it can not return anything for each can iterating main array.
useFul link : use this link for understanding diffrence
https://codeburst.io/javascript-map-vs-foreach-f38111822c0f
Difference between forEach() & map()
forEach() just loop through the elements. It's throws away return values and always returns undefined.The result of this method does not give us an output .
map() loop through the elements allocates memory and stores return values by iterating main array
Example:
var numbers = [2,3,5,7];
var forEachNum = numbers.forEach(function(number){
return number
})
console.log(forEachNum)
//output undefined
var mapNum = numbers.map(function(number){
return number
})
console.log(mapNum)
//output [2,3,5,7]
map() is faster than forEach()
One thing to point out is that both methods skips uninitialized values, but map keeps them in the returned array.
var arr = [1, , 3];
arr.forEach(function(element) {
console.log(element);
});
//Expected output: 1 3
console.log(arr.map(element => element));
//Expected output: [1, undefined, 3];
Performance Analysis (again - not very scientific)
In my experience sometime .map() can be faster than .foreach()
let rows = [];
for (let i = 0; i < 10000000; i++) {
// console.log("here", i)
rows.push({ id: i, title: 'ciao' });
}
const now1 = Date.now();
rows.forEach(row => {
if (!row.event_title) {
row.event_title = `no title ${row.event_type}`;
}
});
const now2 = Date.now();
rows = rows.map(row => {
if (!row.event_title) {
row.event_title = `no title ${row.event_type}`;
}
return row;
});
const now3 = Date.now();
const time1 = now2 - now1;
const time2 = now3 - now2;
console.log('forEach time', time1);
console.log('.map time', time2);
On my macbook pro (late 2013)
forEach time 1909
.map time 444
.map and .forEach will do just about then same thing, until you start operating on arrays with millions of elements. .map will create another collection with the same size (and possibly type, depending on the array species) which could use up a LOT of memory. .forEach will not do this.
const arr = [...Array(100000000).keys()];
console.time("for");
for (let i = 0; i < arr.length; i++) {}
console.timeEnd("for");
console.time("while");
let j = 0;
while (j < arr.length) {
j++;
}
console.timeEnd("while");
console.time("dowhile");
let k = 0;
do {
k++;
} while (k < arr.length);
console.timeEnd("dowhile");
console.time("forEach");
arr.forEach((element) => {});
console.timeEnd("forEach");
VM35:6 for: 45.998046875 ms
VM35:13 while: 154.581787109375 ms
VM35:20 dowhile: 141.97216796875 ms
VM35:24 forEach: 776.469970703125 ms
Map implicitly returns while forEach does not.
This is why when you're coding a JSX application, you almost always use map instead of forEach to display content in React.

How to find all combinations of elements in JavaScript array

I have the following array:
[[A,1,X],[B,2,Y],[C,3,Z]]
I want to be able to get all combinations of the first index of each sub array and then loop through those combinations performing a single task on each. So these are the combinations I'm after (Note I need the combination of the same value as well):
[[A,A],[A,B],[A,C],[B,A],[B,B],[B,C],[C,A],[C,B],[C,C]]
I'd then loop through that and do something with each of the values.
I'm not sure where even to start here so any advice or pointers would be really helpful!
You need to effectively loop through the array twice. Based on what you want you can just statically access the first element each time:
var arr = [['A',1,'X'],['B',2,'Y'],['C',3,'Z']];
var newArr = [];
var length = arr.length;
var curr;
for (var i = 0; i < length; i++) {
curr = arr[i][0];
for (var j = 0; j < length; j++) {
newArr.push([curr, arr[j][0]]);
}
}
console.log(newArr);
Fiddle
Try this:
var data = [['A',1,'X'],['B',2,'Y'],['C',3,'Z']];
function getCombinations(data) {
var combinations = [];
data.forEach(function(first) {
data.forEach(function(second) {
combinations.push([first[0], second[0]]);
});
});
return combinations;
}
console.log(getCombinations(data));
Here is the jsfiddle-demo
Let's decompose the problem. First, let's get extracting the first element of each subarray out of the way:
function get_elts(data, idx) {
return data.map(function(v) { return v[idx]; });
}
So
> get_elts(data, 0) // ['A', 'B', 'C']
Decomposing the problem like this is fundamental to good program design. We don't want to write things which jumble up multiple problems. In this case, the multiple problems are (1) getting the first element of each subarray and (2) finding the combinations. If we write one routine which mixes up the two problems, then we will never be able to re-use it for other things. If our boss comes and says now he wants to find all the combinations of the second element of each subarray, we'll have to cut and paste and create nearly duplicate code. Then we'll be maintaining that code for the rest of our lives or at least until we quit. The rule about factoring is do it sooner rather than later.
Then, create all combinations of any two arrays:
function combinations(arr1, arr2) { //create all combos of elts in 2 arrays by
return [].concat.apply( //concatenating and flattening
[], //(starting with an empty array)
arr1.map( //a list created from arr1
function(v1) { //by taking each elt and from it
return arr2.map( //creating a list from arr2
function(v2) { //by taking each element and from it
return [v1, v2]; //making a pair with the first elt
}
);
};
)
);
}
Normally we would write this more compactly. Let's walk through it:
Array#concat combines one or more things, or elements inside those things if they are arrays, into an array.
Function#apply lets us provide an array that will turn into the argument list of concat.
Array#map creates a parallel array to arr1, which contains...
elements which are two-element arrays based on looping over arr2.
Right, this is not your mother's JavaScript. It's almost a different language from the style where you initialize this and set that and loop over the other thing and return something else. By adopting this style, we end up with code which is more precise, concise, reusable, provably correct, future-friendly, and maybe optimizable.
By future-friendly, I mean among other things ES6-friendly. The above could be rewritten as:
combinations = (arr1, arr2) => [].concat(...arr1.map(v1 => arr2.map(v2 => [v1, v2])));
Get ready guys and girls, this will come up in your job interviews pretty soon now. Time to move on from jQuery.
Now the problem can be expressed as:
var first_elts = get_elts(data, 0);
combinations(first_elts, first_elts);

Removing the elements from one multidimensional array from another multidimensional array

I'm finding it difficult getting my head around what I think is a pretty simple task. My brain is just fried at the moment and I have a deadline. :(
I need to take all the element arrays from one multidimensional array and remove them from another multidimensional array.
Arr1 = [["Tom", "161"], ["Dick", "29"], ["Harry", "46"], ["Mike", "72"], ["Sally", "11"]];
Arr2 = [["Harry", "46"], ["Mike", "72"], ["Tom", "161"]];
So in this instance I want to take all the element arrays from Arr2 and remove them from Arr1 so that afterward Arr1 would look like this:
Arr1 = [["Dick", "29"], ["Sally", "11"]];
Does that make sense?
EDITx2: Wait, no, ignore that, I was being stupid.
Assuming you always have two elements in the array, and a "unique" element is defined as a combination of the name and the number, you can do something like this:
function(array1, array2) {
var seen = {};
var returnedArray = [];
for(var i = 0; i < array2.length; i++) {
var elements = array2[i];
seen[elements[0] + elements[1]] = true;
//an alternative to the above is to do
//seen[JSON.stringify(elements)] = true;
}
for(var i = 0; i < array1.length; i++) {
var elements = array1[i];
if(!seen[elements[0] + elements[1]]) {
returnedArray.push(elements);
}
//an alternative to the above is to do
//if(!seen[JSON.stringify(elements)]) {
// ...
//}
//
//if you took the alternate approach in the first loop
}
return returnedArray;
}
Since it's all strings you could get creative with string methods and chaining. Probably not the best performance and a bit tricky, but it works:
var arr = [["Tom", "161"], ["Dick", "29"], ["Harry", "46"], ["Mike", "72"], ["Sally", "11"]];
var remove = [["Harry", "46"], ["Mike", "72"], ["Tom", "161"]];
var result = arr
.join('|')
.replace(RegExp(remove.join('|'),'g'),'')
.match(/[^|]+/g)
.map(function(s){ return s.split(',') });
console.log(result); //=> [["Dick","29"],["Sally","11"]]
You could even try using JSON. I wouldn't recommend this for production in any case, just for fun.
Demo: http://jsbin.com/obokuy/1/edit
If you need to put together something quick, then use a nested loop to walk through the elements of Arr2 for each element in Arr1 and do a comparison on each. You can look at the answers to this question for a hint on comparing the inner arrays:
How to check if two arrays are equal with JavaScript?

Categories

Resources