I have the following array:
var imagesList = [undefined x 1, cars.jpg, undefined x 1, boats.jpg];
How do I filter out the undefined? so I can get it as follows:
var imagesShow = [cars.jpg, boats.jpg];
I have not found much documentation on getting rid of undefined in an array using javascript.
You could use Array#filter with Boolean as callback for truthy values.
var imagesList = [undefined, 'cars.jpg', undefined, 'boats.jpg'],
imagesShow = imagesList.filter(Boolean);
console.log(imagesShow);
Use Array#filter:
var imagesList = [undefined, 'cars.jpg', undefined, 'boats.jpg'];
var result = imagesList.filter(function(v) {
return v !== undefined;
})
console.log(result);
Try using the Array.filter function
var imagesShow = imagesList.filter(function (value) {
return value != undefined;
};
Any array element that does not pass the check in the callback function above will be filtered out - in this case, if the element is undefined.
Use Array.Filter
var imagesList = [undefined, 'cars.jpg', undefined, 'boats.jpg'];
var result = imagesList.filter(function( element ) {
return element !== undefined;
});
console.log(result);
Try Array.filter() method with ES6 Arrow function expression.
var imagesList = [undefined, "cars.jpg", undefined, "boats.jpg"];
var filteredList = imagesList.filter(item => { return item !== undefined });
console.log(filteredList);
By displaying undefined x 2, your array clearly indicates that it's a sparse one which means you don't have any undefined items. You just don't have the keys to hold items to start with.
OK you may have and wish to keep proper void 0 or undefined items (in which case all of the above solutions will fail) or a numeric value 0 or null object item (in which case the accepted answer will fail).
In order to convert a sparse array to dense form the most efficient method would be a for in loop (or Object.keys()).
So for sparse array looping it's best to use
var res = [],
a = [];
a[1] = "cars.jpg";
a[5] = null;
a[999999] = "beauty.jpg";
// [undefined × 1, "cars.jpg", undefined × 3, null, undefined × 999993, "beauty.jpg"]
function dense(a){
var r = [];
for (i in a) r.push(a[i]);
return r;
}
console.time("test");
res = dense(a);
console.timeEnd("test");
console.log(res);
Now lets compare the above code with an elegant filtering solution;
var res = [],
a = [];
a[1] = "cars.jpg";
a[5] = null;
a[999999] = "beauty.jpg";
// [undefined × 1, "cars.jpg", undefined × 3, null, undefined × 999993, "beauty.jpg"]
console.time("test");
res = a.filter(Boolean);
console.timeEnd("test");
console.log(res);
So as you see null is disappeared and it is slower since it checks all non existing keys. However with for in loop keeping the falsey values or not is totally under your control.
Related
I'm building my own map method to be as close as the native map method.
Since the native map pushes(i think) the changed values into a new array, it still keeps the empty slots. I wasn't able to find a solution to push an empty slot into an array, like this example below.
[1, 2, 3].push(some code) // [1, 2, 3, empty]
I tried pushing an array with one empty item prefixed with a spread operator arr.push(...(new Array(1))) or arr.push(...[,]) but that just pushes undefined.
I solved my problem by not using push and instead assigning values to the array index that way skipped indices will be set to empty.
But I'm writing this post to see if anyone knows that if it's possible to use the push method to push an empty slot to an array.
No, it's not possible, not with the push method. empty can only exist if the array has a certain length, but a whole number property of the array does not exist at some index. This is called a sparse array, and cannot be created with push (or other array methods, if they're called on and with non-sparse arrays).
The only way to do so would be to assign to an index for which a lower index doesn't exist yet.
Look at the results for the below two snippets in your browser console, not the snippet console:
const arr = [];
arr[1] = 'a';
console.log(arr);
Or to set the .length of the array above the last index that the array has:
const arr = [];
arr.length = 1;
console.log(arr);
But the two approaches above are very weird to do and probably have no good reason to be used. Better to avoid sparse arrays entirely.
Keep in mind that an empty slot is different from undefined, which is perfectly possible to have as an array value:
const arr = [];
arr.push(undefined);
console.log(arr);
You can create an empty slot in an array by incrementing the array length:
var a = []
a.push(1)
a.length++
a.push(3)
console.log(a)
console.log(1 in a) // anything at index 1?
Alternatively, you can push something and then delete it:
var a = []
a.push(1)
a.push(2)
a.push(3)
delete a[1]
console.log(a)
console.log(1 in a) // anything at index 1?
There is no need to actually push to a new array in your implementation. You can simply do new Array(this.length) where this.length is the array you are mapping through length.
For example consider this map implementation:
if (!Array.prototype.mapIt) {
Object.defineProperty(Array.prototype, "mapIt", {
value: function(fn) {
if (this === null) {
throw new TypeError('Array.prototype.mapIt called on null or undefined');
}
if (typeof fn !== 'function') {
throw new TypeError('predicate must be a function');
}
let _array = this.filter(x => x != null) // remove empty values
let result = new Array(_array.length) // the new array we will return
for (var i = 0; i < _array.length; i++) {
result[i] = fn.call(arguments[1], _array[i], i, _array) // call the predicate
}
return result;
}
});
}
let arr = [1, 2, , , 3] // the test array
let result = arr.mapIt((c, i, a) =>
console.log(`current: ${c}`, `index: ${i}`, `array: ${a}`) || c + 2)
console.log('result: ', result)
console.log('original array: ', arr)
Hope this helps you with an gives you an idea about a possible map implementation.
I'm trying to complete a problem that involves removing the last item of an array without using the built-in .pop function. Here is the full problem...
Write a function which accepts an array.
The function should remove the last value in the array and return the value removed or undefined if the array is empty.
Do not use the built in Array.pop() function!
Example:
var arr = [1, 2, 3, 4];
pop(arr); // 4
I figured out how to grab the last number with the following code but this obviously doesn't solve the problem.
function pop (array){
for (i=array.length-1; i>array.length-2; i--){
array = array[i]
} return array
}
pop ([1,2,3,4])
Thanks in advance!
A much simpler solution is to just decrease the length of the array by one. No need to create a second array.
function pop (array){
let last = array[array.length-1]; // Store last item in array
array.length = array.length > 0 ? array.length - 1 : 0; // Decrease length
return last; // Return last item
}
// Test function
function logger(ary){
console.log("Original array: " + ary.join(", "), "\n\tItem popped off: " + pop(ary), "\n\tArray contents now: " + ary.join(", "));
}
// Tests
var ary = [1,2,3,4]; logger(ary);
var ary = ["red", "white", "blue", "green"]; logger(ary);
var ary = ["onlyItem"]; logger(ary);
var ary = []; logger(ary);
var ary = [false]; logger(ary);
It seems like simple is better in this case:
const example = [1,2,3,4];
function pop(arr) {
return arr && arr.splice(-1)[0]
}
console.log(pop(example))
console.log(pop(example))
console.log(pop(example))
console.log(pop(example))
console.log(pop(example))
// edge case: should it return undefined or should it throw?
console.log(pop())
EDIT: This includes a null and empty check.
var array = [1, 2, 3, 4, 5];
function pop(array) {
return array && array.splice(-1)[0]
}
console.log(pop(array));
console.log(pop(array));
console.log(pop(array));
console.log(pop(array));
console.log(pop(array));
console.log(pop(array));
console.log(array);
I think what you are looking for is Array.prototype.slice(). You can use the length property of the array to determine whether it is empty and then return the last entry using slice.
const example = [1,2,3,4];
const emptyExample = [];
const pop = group => group.length > 0
? group.slice(group.length - 1)[0]
: undefined;
const answers = [ pop(example), pop(emptyExample) ];
console.log(answers);
Edit from comment
Example should remove from the array while returning last entry so Array.prototype.splice is probably the better function here.
const example = [1,2,3,4];
const emptyExample = [];
const pop = group => (Array.isArray(group) && group.length > 0)
? group.splice(group.length - 1, 1)[0]
: undefined;
const initialExample = [ ...example ];
const answers = [
pop(example),
pop(emptyExample),
{ initialExample, updatedExample: example, emptyExample }
];
console.log(answers);
Array.prototype.splice(start[, deleteCount[, item1[, item2[, ...]]]])
The splice() method changes the contents of an array by removing existing elements and/or adding new elements.
...
Return value: An array containing the deleted elements. If only one element is removed, an array of one element is returned. If no elements are removed, an empty array is returned.
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
What this means is that so long as the input to the function is an instance of Array, we can call Array#splice(-1) to remove the last element. If there are no elements, this will return an empty array. Because we will always be getting either an array with one element or an empty array, we can access the first element using [0]. If the array is empty, this will be undefined.
So, check that that input is an array, then return Array#splice(-1)[0] if it is or undefined if it is not.
function pop(input) {
let output;
if(input instanceof Array) {
output = input.splice(-1)[0]
}
return output
}
function test(input) {
console.log({
before: input && Array.from(input),
popped: pop(input),
after: input
})
return test
}
test( [ 1, 2, 3, 4 ] )( [ 1 ] )( [ ] )( )( [ , , , ] )
You could use Array.splice()
function pop(arr) {
return arr.splice(-1)[0];
}
This will delete the last item in the array and return it.
I create an array with let arr = new Array(99999) but I don't fill it up to arr.length which is 99999, how can I know how much actual, non undefined elements do I have in this array?
Is there a better way than to look for the first undefined?
You could use Array#forEach, which skips sparse elements.
let array = new Array(99999),
count = 0;
array[30] = undefined;
array.forEach(_ => count++);
console.log(count);
The same with Array#reduce
let array = new Array(99999),
count = 0;
array[30] = undefined;
count = array.reduce(c => c + 1, 0);
console.log(count);
For filtering non sparse/dense elements, you could use a callback which returns for every element true.
Maybe this link helps a bit to understand the mechanic of a sparse array: JavaScript: sparse arrays vs. dense arrays.
let array = new Array(99999),
nonsparsed;
array[30] = undefined;
nonsparsed = array.filter(_ => true);
console.log(nonsparsed);
console.log(nonsparsed.length);
The fastest & simplest way to filter items in an array is to... well... use the .filter() function, to filter out only the elements that are valid (non undefined in your case), and then check the .length of the result...
function isValid(value) {
return value != undefined;
}
var arr = [12, undefined, "blabla", ,true, 44];
var filtered = arr.filter(isValid);
console.log(filtered); // [12, "blabla", true, 44]
Suppose I am a user script developer and I don't have control over the on-page javascript. The page creates arrays with random lengths, filling them with random values (including falsy ones, such as undefined). Not every element has to be assigned a value, so there may be empty slots.
A simplified example (Firefox console):
var arr = new Array(3);
arr[0] = null;
arr[1] = undefined;
console.log(arr); \\ Array [ null, undefined, <1 empty slot> ]
console.log(arr[1]); \\ undefined
console.log(arr[2]); \\ undefined
console.log(arr[1] === arr[2]); \\ true
console.log(typeof arr[1]); \\ undefined
console.log(typeof arr[2]); \\ undefined
As we can see, Firefox displays undefined and empty slots differently, whereas for javascript they seem to be identical.
Now suppose I want to clean such an array, removing all empty slots but leaving undefined elements intact. How do I do that?
You can use the in operator to check if the array has a key. It will return false for empty slots, but true for slots with values, including the value undefined:
var arr = new Array(3);
arr[0] = null;
arr[1] = undefined;
1 in arr; // true
2 in arr; // false
Note that you can't distinguish between empty slots and slots past the end of the array using that, but if you know the length of the array, then you already know that 3 isn't part of it, so you don't need to test 3 in arr.
You can also filter out the empty slots like this:
arr = arr.filter( ( _, i ) => i in arr );
You could use Array#forEach, which omits sparse elements.
var arr = new Array(3);
arr[0] = null;
arr[1] = undefined;
console.log(arr);
var withoutSparse = [];
arr.forEach(function (a, i) {
console.log(i);
withoutSparse.push(a);
});
console.log(withoutSparse);
.as-console-wrapper { max-height: 100% !important; top: 0; }
My code
var arr = ['a','b',1];
var results = arr.map(function(item){
if(typeof item ==='string'){return item;}
});
This gives the following results
["a","b",undefined]
I don't want undefined in the results array. How can I do it?
You aren't returning anything in the case that the item is not a string. In that case, the function returns undefined, what you are seeing in the result.
The map function is used to map one value to another, but it looks like you actually want to filter the array, which a map function is not suitable for.
What you actually want is a filter function. It takes a function that returns true or false based on whether you want the item in the resulting array or not.
var arr = ['a','b',1];
var results = arr.filter(function(item){
return typeof item ==='string';
});
Filter works for this specific case where the items are not modified. But in many cases when you use map you want to make some modification to the items passed.
if that is your intent, you can use reduce:
var arr = ['a','b',1];
var results = arr.reduce((results, item) => {
if (typeof item === 'string') results.push(modify(item)) // modify is a fictitious function that would apply some change to the items in the array
return results
}, [])
Since ES6 filter supports pointy arrow notation (like LINQ):
So it can be boiled down to following one-liner.
['a','b',1].filter(item => typeof item ==='string');
You can implement like a below logic.
Suppose you want an array of values.
let test = [ {name:'test',lastname:'kumar',age:30},
{name:'test',lastname:'kumar',age:30},
{name:'test3',lastname:'kumar',age:47},
{name:'test',lastname:'kumar',age:28},
{name:'test4',lastname:'kumar',age:30},
{name:'test',lastname:'kumar',age:29}]
let result1 = test.map(element =>
{
if (element.age === 30)
{
return element.lastname;
}
}).filter(notUndefined => notUndefined !== undefined);
output : ['kumar','kumar','kumar']
My solution would be to use filter after the map.
This should support every JS data type.
example:
const notUndefined = anyValue => typeof anyValue !== 'undefined'
const noUndefinedList = someList
.map(// mapping condition)
.filter(notUndefined); // by doing this,
//you can ensure what's returned is not undefined
You only return a value if the current element is a string. Perhaps assigning an empty string otherwise will suffice:
var arr = ['a','b',1];
var results = arr.map(function(item){
return (typeof item ==='string') ? item : '';
});
Of course, if you want to filter any non-string elements, you shouldn't use map(). Rather, you should look into using the filter() function.
If you have to use map to return custom output, you can still combine it with filter.
const arr = ['a','b',1]
const result = arr.map(element => {
if(typeof element === 'string')
return element + ' something'
}).filter(Boolean) // this will filter out null and undefined
console.log(result) // output: ['a something', 'b something']
var arr = ['a','b',1];
var results = arr.filter(function(item){
if (typeof item ==='string') {return item;}
});
If you use it like this, your problem will be solved.
Also, you will have a clean and short code
var _ = require('lodash'); //but first, npm i lodash --save
var arr = ['a','b',1];
var results = _.compact(
_.map(arr, function(item){
if(_.isString(item)){return item;}
}
); //false, null, undefined ... etc will not be included
with ES6...
const _ = require('lodash'); //but first, npm i lodash --save
const arr = ['a','b',1];
const results = _.compact(
_.map(arr, item => {
if(_.isString(item)){return item;}
}
);
I run into this quite frequently where the type after filtering will still be string | number. So, to expand upon these solutions and include type safety you can use a user-defined type guard.
https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates
const result = ['a','b',1].filter((item) => typeof item ==='string');
// result is typed as (string | number)[]
Better type safety using user-defined type guard
const result = ['a','b',1].filter((item): item is string => typeof item ==='string');
// result is now typed as string[]
The problem:
the issue is arr.map() will do a full iteration of arr array length, i.e. map() method will loop as much as the length of arr is, no matter what condition you have inside it, so if you defined a condition inside it e.g. if(typeof item ==='string'){return item;} even if the condition is not happening, the map() will be forced to keep looping until finishing the looping of the whole arr so it will give you undefined for the rest of elements if the condition is not met.
The solutions:
Solution One: if you want to return the whole item in the array when the condition is met, you can use arr.filter() so the filter will return the whole item for the iteration e.g. if you have array of objects like bellow
const arr = [{name: "Name1", age: 25}, {name: "Name2", age: 30}, {name: "Name3", age: 25}]
and you want to return the whole objects when the condition is met like example below
const filteredItems = arr.filter((item)=>{if(item.age === 25){return true}})
console.log(filteredItems) //results: [{name: "Name1", age: 25}, {name: "Name3", age: 25}]
conclusion: filter() method returns an array of the whole items in it if the condition is met.
Solution Two: if you want to return only a specific data of the objects (or the whole object or any shape of data) in array i.e. if you want to return only the names in array without the ages, you can do this
const namesOnly = arr.map((item)=>{if(item.age === 25){return item.name}})
console.log(namesOnly) //results: ["Name1, udefined, "Name3"]
now to remove the undefined you just use filter() method on the results like below
const namesOnly = arr.map((item)=>{if(item.age === 25){return item.name}}).filter((item)=> !!item)
console.log(namesOnly) //results: ["Name1, "Name3"]
conclusion: map() method returns an array of specifically defined data in the return, and returns undefined if the condition is not met. so then we can use filter() method to remove the undefined.
You can filter records with .map easily using below example code
const datapoints = [
{
PL_STATUS: 'Packetloss',
inner_outerx: 'INNER',
KPI_PL: '97.9619'
},
{
PL_STATUS: 'Packetloss',
inner_outerx: 'OUTER',
KPI_PL: '98.4621',
},
{
PL_STATUS: 'Packetloss',
inner_outerx: 'INNER',
KPI_PL: '97.8770',
},
{
PL_STATUS: 'Packetloss',
inner_outerx: 'OUTER',
KPI_PL: '97.5674',
},
{
PL_STATUS: 'Packetloss',
inner_outerx: 'INNER',
KPI_PL: '98.7150',
},
{
PL_STATUS: 'Packetloss',
inner_outerx: 'OUTER',
KPI_PL: '98.8969'
}
];
const kpi_packetloss_inner: string[] = [];
datapoints.map((item: { PL_STATUS: string; inner_outerx: string; KPI_PL: string }) => {
if (item.PL_STATUS === 'Packetloss' && item.inner_outerx === 'INNER') {
kpi_packetloss_inner.push(item.KPI_PL);
}
})
console.log(kpi_packetloss_inner);
Map is used when you want to produced new modified array from the original array.
the simple answer may be for someone
var arr = ['a','b',1];
var results = arr.filter(function(item){
// Modify your original array here
return typeof item ==='string';
}).filter(a => a);