Reputation: 4620
I have an array of arrays and each of those arrays contain two elements. How can I return the second element from array by filtering the first element?
For example I have the following array and my function should return the second element from each sub-array where the first item is 8
:
var array = [[8, 'first'], [8, 'second'], [1, 'empty'], [8, 'third'], [9, 'empty']];
Expected result: ['first', 'second', 'third']
This is what I've implemented so far, but it returns both elements instead of just the second one from each array with a match...
var array = [[8, 'first'], [8, 'second'], [1, 'empty'], [8, 'third'], [9, 'empty']];
var result = array.filter(function(item){
if(item[0] == 8) {
return item[1];
}
});
console.log(result);
Upvotes: 2
Views: 24029
Reputation: 1724
Array.prototype.filter
returns element that passes provided predicate, so in you case that will be item
for which item is true. To achieve what you want, you need to filter items first and the extract second element using map
:
var array = [[8, 'first'], [8, 'second'], [1, 'empty'], [8, 'third'], [9, 'empty']];
var result = array.filter(function(item) {
return item[0] == 8;
}).map(function (item) {
return item[1];
});
console.log(result);
Or use reduce:
var array = [[8, 'first'], [8, 'second'], [1, 'empty'], [8, 'third'], [9, 'empty']];
var result = array.reduce(function(result, item) {
return item[0] == 8 ? result.concat(item[1]) : result;
}, []);
console.log(result);
If you want to use features of ES6 it can get event shorter:
const array = [[8, 'first'], [8, 'second'], [1, 'empty'], [8, 'third'], [9, 'empty']];
const result1 = array.filter(([item]) => (item == 8)).map(([,item]) => item);
const result2 = array.reduce((res, [n, str]) => n == 8 ? [...res, str] : res, []);
console.log(result1);
console.log(result2);
EDIT: To understand why your function is not working you need to understand how Array.prototype.filter()
works. It creates a new array made of elements for which provided predicate function (i.e. checking some condition and returning Boolean) returns true. For all sub-arrays that have 8
as first item, second element will decide if that element will be used for creating new array.
So for each element of array
(first [8, 'first']
, next [8, 'second']
etc.) your function will be evaluated, and element for which true is returned, will be added to new array:
[[8, 'first'], [8, 'second'], [1, 'empty'], [8, 'third'], [9, 'empty']]
true, true, false, true, false
=> [[8, 'first'], [1, 'empty'], [8, 'third']]
Upvotes: 2
Reputation: 99
You can utilize Array.reduce to achieve your desired output -
var array = [[8, 'first'], [8, 'second'], [1, 'empty'], [8, 'third'], [9, 'empty']];
array.reduce(function(i, n){
if(n[0]==8){
i.push(n[1]);
}
return i;
},[]);
//output : ['first', 'second', 'third']
Upvotes: -2
Reputation: 386604
You could filter with the condition and then you need to map only the part, you want.
In a single loop it is only possible with Array#reduce
, because here you can manipulate the value for the result set.
Array#filter
returns the original item of the array, without changing something.
The
filter()
method creates a new array with all elements that pass the test implemented by the provided function.
For filtering, the callback needs to return a value which is interpreted as boolean, that means, every truthy value (like an object, array, or any not zero number, etc) takes the item for the result set.
If you like to use only a part of the inner array and the part is a truty value, then filtering works, but it does not take the return value, because it is not made for that.
var array = [[8, 'first'], [8, 'second'], [1, 'empty'], [8, 'third'], [9, 'empty']],
result = array.filter(function(item){
return item[0] === 8;
}).
map(function (a) {
return a[1];
});
console.log(result);
Upvotes: 4
Reputation: 99
You could use function reduce
var array = [[8, 'first'], [8, 'second'], [1, 'empty'], [8, 'third'], [9, 'empty']];
var result = array.reduce(function(acc, item){
if(item[0] === 8){
acc.push(item[1])
}
return acc;
}, []);
console.log(result);
Array#reduce It will finish in a single loop.
Upvotes: 1
Reputation: 1074335
You need to both filter out the entries you don't want and map the entries to just the second value in the entry.
In general, the best way is to filter
then map
:
var array = [[8, 'first'], [8, 'second'], [1, 'empty'], [8, 'third'], [9, 'empty']];
var result = array.filter(function(item){ return item[0] == 8; })
.map(function(item) { return item[1]; });
console.log(result);
...but for a really large data set, if you don't want to make multiple passes, you can give yourself a filterMap
function:
function filterMap(arr, predicate) {
var result = [];
arr.forEach(function(entry) {
var newEntry = predicate(entry);
if (newEntry !== undefined) {
result.push(newEntry);
}
});
return result;
}
var array = [[8, 'first'], [8, 'second'], [1, 'empty'], [8, 'third'], [9, 'empty']];
var result = filterMap(array, function(item){
return item[0] == 8 ? item[1] : undefined;
});
console.log(result);
That version assumes you never want an undefined
entry in the result, but you can tweak as desired. For instance, if you want it to be really general purpose, you'd put a unique value on filterMap
which indicated "leave this out":
function filterMap(arr, predicate) {
var result = [];
arr.forEach(function(entry) {
var newEntry = predicate(entry);
if (newEntry !== filterMap.OMIT) {
result.push(newEntry);
}
});
return result;
}
filterMap.OMIT = {};
var array = [[8, 'first'], [8, 'second'], [1, 'empty'], [8, 'third'], [9, 'empty']];
var result = filterMap(array, function(item){
return item[0] == 8 ? item[1] : filterMap.OMIT;
});
console.log(result);
While you can shoehorn reduce
to do this, reduce
isn't really great for situations where the "accumulator" doesn't change. So if you do this frequently, give yourself a utility to do it. Or just filter
and map
.
Upvotes: 0
Reputation: 5950
First map, then filter to remove undefined values.
var array = [[8, 'first'], [8, 'second'], [1, 'empty'], [8, 'third'], [9, 'empty']];
var result = array.map(function(item){
if(item[0] == 8) {
return item[1];
}
}).filter(function(item) {
return item;
});
console.log(result);
Upvotes: 0
Reputation: 265
Array's filter method creates a new array by passing the item that pass certain condition in each iteration.
Try out this:
var array = [[8, 'first'], [8, 'second'], [1, 'empty'], [8, 'third'], [9,
'empty']],resArray = [];
array.forEach(function(item){
if(parseInt(item[0]) === 8){
resArray.push(item[1]);
}
});
console.log(resArray);
Upvotes: 0