I need to group array items, if they are the same. But only, if they follow after another.
Single items without same value before or after should be ignored.
Example:
const array = [
{country : 'usa', continent: 'north america'},
{country : 'germany', continent: 'europe'},
{country : 'france', continent: 'europe'},
{country : 'india', continent: 'asia'},
{country : 'netherlands', continent: 'europe'},
]
The result should be:
[
{country : 'usa', continent: 'north america'},
[
{country : 'germany', continent: 'europe'},
{country : 'france', continent: 'europe'}
],
{country : 'india', continent: 'asia'},
{country : 'netherlands', continent: 'europe'},
]
]
This solution also would work:
[
{country : 'usa', continent: 'north america'},
{grouped: 'continent', countries: [
{country : 'germany', continent: 'europe'},
{country : 'france', continent: 'europe'}
]
},
{country : 'india', continent: 'asia'},
{country : 'netherlands', continent: 'europe'},
]
]
CodePudding user response:
This should do it.
There is a blank new array which stores the answer.
The algorithm just iterates through the existing array saving a temporary array of matches. When the next entry does not match the previous, it adds that temporary array to a new array.
const array = [{
country: 'usa',
continent: 'north america'
},
{
country: 'germany',
continent: 'europe'
},
{
country: 'france',
continent: 'europe'
},
{
country: 'india',
continent: 'asia'
},
{
country: 'netherlands',
continent: 'europe'
},
]
const newArray = []
var tempArray = []
var previousContinent = ""
array.forEach(item => {
if (item.continent === previousContinent) {
tempArray.push(item)
} else {
// Delete this first check if you don't mind every entry being an array
if (tempArray.length === 1) {
newArray.push(tempArray[0])
} else if (tempArray.length > 0) {
newArray.push(tempArray)
}
previousContinent = item.continent
tempArray = [item]
}
})
console.log(newArray)
CodePudding user response:
Since you have the condition for two countries to be grouped in the same continent they should be adjacent siblings, the quickest way to produce that result and visit the input array only once, is keeping track of the previous continent and fill a queue of countries to push in the output all at once when the next input country breaks the chain.
This demo will output on console the result array crafted as described before:
const array = [
{country : 'usa', continent: 'north america'},
{country : 'germany', continent: 'europe'},
{country : 'france', continent: 'europe'},
{country : 'india', continent: 'asia'},
{country : 'netherlands', continent: 'europe'},
];
function groupCountries(array, useWrapper = false){
let result = [];
let prevContinent;
let queueToFlush = [];
array.forEach((o, i)=>{
if(typeof prevContinent !== "undefined" && prevContinent != o.continent){
//if the queue has more than one country
if(queueToFlush.length > 1){
//if useWrapper was passed to the function as true
if (useWrapper){
//overwrites queueToFlush with the new wrapper object
queueToFlush = {
grouped : o.continent,
countries : queueToFlush
};
}
//adds the queue to the result
result.push(queueToFlush);
//otherwise if there's one country only
}else{
//adds the single country to the result
result.push(queueToFlush[0]);
}
//resets the queue
queueToFlush = [];
}
queueToFlush.push(o);
prevContinent = o.continent;
});
return result;
}
let result;
//first fashion
result = groupCountries(array);
console.log(result);
//second fashion
result = groupCountries(array, true);
console.log(result);
CodePudding user response:
One method would be to loop through the array and store last continent
value, if it's the same as previous item, then move previous item into an array and add current item into it.
Array.reduce()
could be used for this task:
const array = [
{country : 'usa', continent: 'north america'},
{country : 'germany', continent: 'europe'},
{country : 'france', continent: 'europe'},
{country : 'india', continent: 'asia'},
{country : 'netherlands', continent: 'europe'},
];
const newArray = array.reduce((map, item) =>
{
let prevItem = map[map.length-1]; //get prevous item
// is previous continent matches current?
if (prevItem && (prevItem.continent || (prevItem[0] && prevItem[0].continent)) === item.continent)
{
if (prevItem.continent) //if it's not an array, convert it into one
{
prevItem = [prevItem]; //convert prevous item into array
map.splice(-1, 1, prevItem); //replace prevous item with new array'ed item
}
prevItem[prevItem.length] = item; //append current item to the array
}
else
map[map.length] = item;
return map;
}, [] /* "map" array */);
console.log(newArray);