Reputation: 95
I have js object like this
var continents = [
0: {
short: 'na',
countries: [
{
name: 'canada'
},
{
name: 'usa'
},
//...
]
},
1: {
short: 'sa',
countries: [
{
name: 'chile'
},
{
name: 'colombia'
}
]
},
//...
]
I want to filter this object for matches with country name (contents.countries.name) with some string (example 'col') Example filter function
filter(item => {
return item.name.toLowerCase().indexOf('col'.toLowerCase()) >= 0;
});
Expecting result:
1: {
short: 'sa',
countries: [
{
name: 'colombia'
}
]
}
Upvotes: 3
Views: 143
Reputation: 386868
You could try to filter the countries and if one found, push the outer continent as well to the result set.
function getItems(name) {
var result = [];
continents.forEach(function (continent) {
var countries = continent.countries.filter(function (country) {
return country.name.startsWith(name);
});
if (countries.length) {
result.push({ short: continent.short, countries: countries });
}
});
return result;
}
var continents = [{ short: 'na', countries: [{ name: 'canada' }, { name: 'usa' }] }, { short: 'sa', countries: [{ name: 'chile' }, { name: 'colombia' }] }];
console.log(getItems('col'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 0
Reputation: 4918
For a loop you could use:
var continents = [
{
short: 'na',
countries: [
{
name: 'canada'
},
{
name: 'usa'
}
]
},
{
short: 'sa',
countries: [
{
name: 'chile'
},
{
name: 'colombia'
}
]
}
];
var results = continents.filter(item => {
for (let x = 0; x < item.countries.length; x++) {
if (item.countries[x].name.toLowerCase().indexOf('usa') > -1) {
return item;
break;
}
}
});
console.log(results);
Working example: https://jsfiddle.net/gugui3z24/fnw5kf0x/2/
Upvotes: 0
Reputation: 1540
You can use the filter
function to return just the items that match a condition. Like so:
const matches = [];
continents.forEach((continent) => {
const countries = continent.countries.filter((country) => {
return country.name.includes('col');
});
matches.push(...countries);
});
Note: I have used the spread
operator ...
to flattern the array (avoiding an array of arrays).
Upvotes: 0
Reputation: 48751
You need to not only filter on the continents, but the countries within them.
This is a two-part filter, as seen below.
var continents = [{
short: 'na',
countries: [
{ name: 'canada' },
{ name: 'usa' }
]
}, {
short: 'sa',
countries: [
{ name: 'chile' },
{ name: 'colombia' }
]
}];
function filterByKeyValue(arr, keys, val) {
return arr.filter(item => {
return item[keys[0]].some(subitem => subitem[keys[1]].indexOf(val) > -1);
}).map(item => {
item[keys[0]] = item[keys[0]].filter(subitem => subitem[keys[1]].indexOf(val) > -1);
return item;
});
}
var filtered = filterByKeyValue(continents, [ 'countries', 'name' ], 'col');
console.log(filtered);
.as-console-wrapper { top: 0; max-height: 100% !important; }
<!--
Original filter that method is based on.
var filtered = continents.filter(continent => {
return continent.countries.some(country => country.name.indexOf('col') > -1);
}).map(continent => {
continent.countries = continent.countries.filter(country => country.name.indexOf('col') > -1);
return continent;
});
-->
Upvotes: 1
Reputation: 4918
item in this case has two properties, countries and short. You are trying to run .name on item, which doesn't exist. You need to run .name on either item.countries[0].name or item.countries[1].name.
var continents = [
{
short: 'na',
countries: [
{
name: 'canada'
},
{
name: 'usa'
}
]
},
{
short: 'sa',
countries: [
{
name: 'chile'
},
{
name: 'colombia'
}
]
}
];
var results = continents.filter(item => {
return item.countries[0].name.toLowerCase().indexOf('col'.toLowerCase()) >= 0 ||
item.countries[1].name.toLowerCase().indexOf('col'.toLowerCase()) >= 0
});
console.log(results);
Working example: https://jsfiddle.net/gugui3z24/fnw5kf0x/
Upvotes: 0