.map() is storing unwanted undefined values into new array [duplicate] - javascript

This question already has answers here:
Why does JavaScript map function return undefined?
(13 answers)
Closed 3 years ago.
Simple array declaration:
let sodas = ["Sprite", "Coke", "Mountain Dew", "Dr. Pepper", "Sunkist"];
I want to use .map() function to create a new array containing sodas only owned by the CocaCola Company, and then display this new array in the console -
let cocacola_sodas = sodas.map(soda => {
if ((soda == "Coke") || (soda == "Sprite")) {
return soda;
}
})
console.log(cocacola_sodas);
This code seems to work, though I'm not sure why it is returning 5 new elements into cocacola_sodas array when only 2 of them should be returned (coke and sprite). The array will display ["Sprite", "Coke", undefined, undefined, undefined]. Why is it returning undefined values?

#awoldt, to help you understand what is actually happening, Array.prototype.map will always return the same number of elements from the input array to a new array.
so best way to think about it is you give map an array with x elements, regardless of what you do to those elements inside the block you pass to map, it will always return X # of elements in the new array.
As was suggested, something like filter/reduce will return a new array with just the elements that meet the criteria you set out int he block passed to those helpers
you can read more about map and all the Array.prototype.methods at MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map

Use filter instead of map. It was made or use in situations like this. As pointed by other answers map will always return the same number of elements as present in the input array
let sodas = ["Sprite", "Coke", "Mountain Dew", "Dr. Pepper", "Sunkist"];
let cocacola_sodas = sodas.filter(soda => {
if ((soda == "Coke") || (soda == "Sprite")) {
return soda;
}
})
console.log(cocacola_sodas);

To elaborate on #ellipsis answer:
The reason filter is better here is because it is generating a new array of items not filtered out of the original array.
The reason map is giving you the results you see are because it's not filtering, but changing each element and giving it to the result array. I think a code example would help to clarify.
Map might look something like this under the hood:
var array = ['one', 'two', three];
var mapFunc = function(item) {
if(item == 'two')
return item;
};
var mappedArray = [];
for(var i = 0; i < array.length; i++)
mappedArray.push(mapFunc(array[i]));
Obviously the above is simplified to be clear, but as you can see the mapped array will have as many items in it as the original array. Since you return nothing in the case item doesn't equal two then you return undefined hence why you have the extra items in your example.

The includes() method determines whether an array includes a certain value among its entries, returning true or false as appropriate.
let sodas = ["Sprite", "Coke", "Mountain Dew", "Dr. Pepper", "Sunkist"];
let cocaCola = ["Coke","Sprite"];
let cocacola_sodas = sodas.filter(soda => cocaCola.includes(soda))
console.log(cocacola_sodas);

Related

How do I filter through an array of arrays using an index in JavaScript? [duplicate]

This question already has an answer here:
javascript filter multidimensional array
(1 answer)
Closed 1 year ago.
Im'm working on a JavaScript side prokect and I've got a json file with an array with arrays like this:
arr =
{
"values": [
["Form Factor", "OS"],
["Landscape", "Android 9\n(Source)"],
["Portrait", "Analogue OS"],
["Micro\nLandscape", "?"]
]
}
The first array with "Form factor" (index 0) are the headlines. If I want to get all the "form factors" from the arrays how would I do that?
I know that "Form Factor" has index 0 but how do i filter through several arrays at once with an index? in the end I want an array like
results = ["Form Factor", "Landscape", "Portrait", "Micro\nLandscape"]
I tried it like this:
const index = 0;
const result = this.arr.values.filter(function (eachElem) {
return eachElem == index;
});
But that just gives me back an empty array.
Don't forget to check this
arr.values.map(x => x[0])
Your code isn't working because a) index isn't defined, you need to also put it as a parameter and b) in your case no element will be true.
I would use a traditional for loop in your case but surely if you want you can do it with es6 magic.
let result = [];
for (let i = 0; i < arr.values.length; i++) {
result.push(arr.values[i][0]);
}
console.log(result);
Just use array.find() it's much easier and you can search for your element in your array:
const found = array1.find(element => element > 10);

Javascript Grammer: how to assign correct values to an array of objects [duplicate]

This question already has answers here:
new Array(_).fill(object) does not create new instances of object [duplicate]
(5 answers)
Array.prototype.fill() with object passes reference and not new instance
(7 answers)
Closed 2 years ago.
let's look at the code:
Test() {
let array1 = new Array(5).fill({ a: 0 })
let array2 = new Array(5).fill({ a: 0 })
for (let i = 0; i < 5; i++) {
setTimeout(() => {
array1[i].a = i
array2[i] = {a:i}
console.warn("array = ", array1)
console.warn("array2 = ", array2)
}, 0.2 * i)
}
}
In this case, I wanna assign a series of values to the array1 & array2, and there are two ways to do it, which lead to totally different results.
In the case array1[i].a = i, after all the code is ran, the result is array = [{a:4},{a:4},{a:4},{a:4},{a:4}], which is not what i wanted.
In the second case array2[i] = {a:i}, the result will be [{a:0},{a:1},{a:2},{a:3},{a:4}] as expected.
I wanna know why is it like this? What's the machanics behind this phenomenon?
Thank you.
When you call .fill() and pass an object, you assign the exact same object to every element of the array. Thus, modifying a property at one array index modifies the same property at all the other indexes, because they're all pointing to the same thing.
There are a variety of ways around this issue. You could fill the array with 0 or null or some dummy value and then iterate through with .forEach(), or more simply just use an indexed for loop to initialize each element. If you initialize with { a: 0} in a for loop, a new object will be created on each iteration.

Chaining methods on array display as undefined [duplicate]

This question already has answers here:
How can I create a two dimensional array in JavaScript?
(56 answers)
Closed 5 years ago.
const array = new Array(9).fill([]).forEach(function(value, index, arr) {
arr[index] = Array(9).fill(0);
console.log(index, arr[index]); // This line report properly by creating
}); // new array.
console.log(array); // Reported as underdefined.
However, if redefine as below, it works as expected.
const array = new Array(9).fill([]);
array.forEach( function(value,index,arr){
arr[index] = Array(9).fill(0);
console.log(index,arr[index]);
});
console.log(array);
I would like to define multiple dimensional arrays within one line used as this state command.
But what is the problem for scenario 1 where bounded forEach methods array definitions work fine?
But what is the problem for scenario 1 where bounded forEach methods
array defnitions works fine.
Problem is forEach returns undefined
I woule like to define multiple dimensional arrays within one line
used as this.state command.
You can use map for the same
var output = new Array(9).fill([]).map( function(value,index,arr){
return Array(9).fill(0); //return the inner array
});
Or as #bergi suggested, you can use Array.from as well
var output = Array.from(Array(9)).map( function(value,index,arr){
return Array(9).fill(0);
});
As other answers have already mentioned Array.forEach returns undefined or does not return anything, you cannot use it.
As an alternate approach, you can use Array.from.
Following is a sample:
var output = Array.from({
length: 9
}, () => {
return Array.from({
length: 9
}, () => 0)
});
console.log(output)
Also, one more issue with your code is, you are using an object in Array.fill. What array.fill does is, it will create the value to be filled first and then fill it in all items.
var output = new Array(9).fill([]);
output[0].push(1);
console.log(output)
In you check the output, it says /**ref:2**/, but if you check in console, you will notice that all items will have item 1. So you should avoid using objects with Array.fill.
You want to generate array of 9 arrays filled with 0 and return it to variable.
You can achieve this using map method.
const array =
new Array(9)
.fill([])
.map(function(){
return Array(9).fill(0);
});
console.log(array);
p.s. no value, index and etc needed to pass to map methods argument in Your case
Array.prototype.forEach returns undefined. Just call the forEach like below.
const array = new Array(9).fill([])
array.forEach( function(value,index,arr){
arr[index] = Array(9).fill(0);
});
// [
// [0, 0, 0, ...],
// ...
// ]
Using map would be another choice, but I don't vote for it because it creates yet another array in memory.

Looping through an array with conditions

I'm having a tough time figuring out how to loop through an array and if certain items do exist within the array, i'd like to perform a .slice(0, 16) to kind of filter an already existing array (lets call that existing array "routes").
For example, a previous process will yield the following array:
points = ['=00ECY20WA200_RECV_P1SEL',
'=00ECY20WA200_RECV_P2SEL',
'=00RECV_C1A_EINCSCMPP1',
'=00RECV_C1A_EINCSCMPP2',
'=00BYPS_C1A_EINCSCMP',
'=00ECY20WA200_BYPS_SPSL1',
'=00ECC92AG184YB01',
'=00ECC92AG185YB01',
'=00ECC92AG186YB01',
'=00ECC92AG187YB01',
]
So if any of the above items exist in the "points" Array, which in this case they all do (but in some cases it could just be 1 of the 10 items existing there), I'm trying to perform routes.slice(0, 16) to the other already existing array.
I've tried lots of different ways (for loops with if statements) and at this point I'm not sure if its my syntax or what, but I'm back at square 0 and I don't even have a competent piece of code to show for. Any direction would be greatly appreciated.
You could use a hash table for checking and filtering.
var points = ['=00ECY20WA200_RECV_P1SEL', '=00ECY20WA200_RECV_P2SEL', '=00RECV_C1A_EINCSCMPP1', '=00RECV_C1A_EINCSCMPP2', '=00BYPS_C1A_EINCSCMP', '=00ECY20WA200_BYPS_SPSL1', '=00ECC92AG184YB01', '=00ECC92AG185YB01', '=00ECC92AG186YB01', '=00ECC92AG187YB01'],
hash = Object.create(null),
filtered = points.filter(function (a) {
if (!hash[a.slice(0, 16)]) {
hash[a.slice(0, 16)] = true;
return true;
}
});
console.log(filtered);
ES6 with Set
var points = ['=00ECY20WA200_RECV_P1SEL', '=00ECY20WA200_RECV_P2SEL', '=00RECV_C1A_EINCSCMPP1', '=00RECV_C1A_EINCSCMPP2', '=00BYPS_C1A_EINCSCMP', '=00ECY20WA200_BYPS_SPSL1', '=00ECC92AG184YB01', '=00ECC92AG185YB01', '=00ECC92AG186YB01', '=00ECC92AG187YB01'],
pSet = new Set,
filtered = points.filter(a => !pSet.has(a.slice(0, 16)) && pSet.add(a.slice(0, 16)));
console.log(filtered);
EDIT: So it seems like you want to remove an element from an array called routes for each element in the points array. This is how you could do this:
function removeBrokenRoutes(brokenPoints, routes){
for(let pt of brokenPoints){
let index = routes.indexOf(pt);
if(index !== -1) routes.splice(index,1);
}
return routes;
}
Keep in mind that the larger the arrays, the more time this is going to take to complete.
You could use the filter and indexOf methods in combination:
var arr = [/* all the data you're checking against */];
var points = [/* the data you're checking for */];
var filteredArr = arr.filter(function(x) {
// will return -1 if the point is not found
return points.indexOf(x) !== -1;
});
filteredArr will contain all the points that appear in both arrays. The filter function works by taking a function with one argument x, which represents each item in the array. if the function returns true, the item will be added to the new array (filteredArr), and if false the function will move on to the next item. indexOf will check if the item is found in the other array. Also it is important to note that you will need a more complex solution (such as a hashtable) if the data set is very, very large as this is not necessarily the most performant method. But it's a good place to start as it is easy to understand.

Check if an object has a key in javascript

I have two arrays of objects, and I want to filter the first one according to whats on the second one. Here's an example:
var ary1 = [{id: 23, title: 'blabla'},{id:43, title: 'bleble'}, {id:54, title:'blibli'}];
var ary2 = [{id:23},{id:54}, {id:65}];
So in this case what I want to return is an array with the objects that have id's 23 and 54 of the first array, with all its possible properties (in this case, title).
Could you give me any hint that could help me?
Get a list of the indexes you want to search on using map:
var indexes = ary2.map(function (el) {
return el.id;
});
filter the results based on the list of indexes:
var result = ary1.filter(function (el) {
return indexes.indexOf(el.id) > -1;
});
DEMO
This might help you.
Loop through ary2, building up an array of each id value (let's call this array existingIds).
After that loop, now loop through ary1. For each item in ary1, check to see if the id value exists in the existingIds array that we just built up. If it does, append the current item to a result array.
I could write the code for you, but it will be a better learning experience if you first try this yourself :)
Might as well make use of some functional programming built into javascript.
filteredResults = ary1.filter(function(ele){
return (ary2.map(function(idobj){return idobj.id;}).indexOf(ele.id)>-1)
})
filter(function) will iterate through each element of an array, passing it through a callback function. From within that callback iff a true is returned, that value is kept. If false, that value is filtered out.
Also map(function) will iterate through each element of an array passing a callback value as well. All values returned from map callback will be injected into the result. So we can take the id from each element in ary2 and return it in the map function.
var ary1 = [{id: 23, title: 'blabla'},{id:43, title: 'bleble'}, {id:54, title:'blibli'}];
var ary2 = [{id:23},{id:54}, {id:65}];
//Filter for the available ID's, store the resulting objects in a new array
filteredResults = ary1.filter(function(ele){
//map creates an array of just ID's
return (ary2.map(function(idobj){return idobj.id;}).indexOf(ele.id)>-1)
})
//now do whatever you were planning on doing with your results/
var res = document.getElementById("results");
filteredResults.forEach(function(ele){
res.innerHTML+="<li>{id:"+ele.id + ",title:" +ele.title+"}</li>"
})
console.log(filteredResults);
<ul id="results"></ul>
try this:
var ary1 = [{id: 23, title: 'blabla'},{id:43, title: 'bleble'}, {id:54, title:'blibli'}];
var ary2 = [{id:23},{id:54}, {id:65}];
var newary=[];
for(x in ary1){
for(y in ary2){
if(ary1[x].id == ary2[y].id){
newary.push(ary1[x]);
}
}
}
console.log(newary);// here newary will be your return newary;

Categories

Resources