2

I have a base array like below.

const arr1 = [
{id:'1',city:'Sydney',distance:100,yearhalf:'2022_1'},
{id:'2',city:'Melbourne',distance:70,yearhalf:'2022_1'},
{id:'3',city:'Perth',distance:65,yearhalf:'2022_1'},
{id:'4',city:'Sydney',distance:89,yearhalf:'2022_2'},
{id:'5',city:'Melbourne',distance:40,yearhalf:'2022_2'},
{id:'6',city:'Perth',distance:40,yearhalf:'2022_2'}
]

The idea is to group the array elements by "yearhalf".I can achieve that with below approach.

const groupedArray = arr1((acc,item)=>{
        const itemIndex = acc.findIndex(i=>i.yearhalf === item.yearhalf);

        if(itemIndex !== -1){
            acc[itemIndex][item.city]=[item.distance]
        }
        else{
          acc.push({
             [item.city]:[item.distance],
             yearhalf:item.yearhalf
          })
        }
        return acc;
      },[])

The result array will be like below. Currently at this level.

[
{yearhalf:'2022_1',Sydney:[100],Melbourne:[70],Perth:[65]},
{yearhalf:'2022_2',Sydney:[89],Melbourne:[40],Perth:[40]},
]

What I want to do is, if there are multiple occurrences of same "city" and same "yearhalf" combinations(with different id field of course), push only those distances to existing results. So having additional entries like below in the initial array(arr1) would change the above result.

{id:'7',city:'Sydney',distance:50,yearhalf:'2022_1'},
{id:'8',city:'Melbourne',distance:40,yearhalf:'2022_1'}

Since we already have a yearhalf named '2022_1' it should add the city distance to the already existing cityname(Sydney/Melbourne etc) array like below

[
{yearhalf:'2022_1',Sydney:[100,50],Melbourne:[70,40],Perth:[65]},
{yearhalf:'2022_2',Sydney:[89],Melbourne:[40],Perth:[40]},
]

Note: The city name will always be one of Sydney/Melbourne/Perth. Year halves can be have more instances(YYYY_1,YYYY_2) but since initially grouping by them shouldn't cause much of a problem.

Thanks in advance!

2 Answers 2

1

You could check for the array and assign if necessary.

const
    arr1 = [{ id: '1', city: 'Sydney', distance: 100, yearhalf: '2022_1' }, { id: '2',city: 'Melbourne', distance: 70, yearhalf: '2022_1' }, { id: '3', city: 'Perth', distance: 65, yearhalf: '2022_1' }, { id: '4', city: 'Sydney', distance: 89, yearhalf: '2022_2' }, { id: '5', city: 'Melbourne', distance: 40,yearhalf: '2022_2' },  { id: '6', city: 'Perth', distance: 40, yearhalf: '2022_2' }, { id: '7', city: 'Sydney', distance: 50, yearhalf: '2022_1' }, { id: '8', city: 'Melbourne', distance: 40, yearhalf: '2022_1' }],
    groupedArray = arr1.reduce((acc, { city, distance, yearhalf }) => {
        const itemIndex = acc.findIndex(i => i.yearhalf === yearhalf);
        if (itemIndex === -1) {
            acc.push({ yearhalf, [city]: [distance] });
        } else {
            (acc[itemIndex][city] ??= []).push(distance);
        }
        return acc;
    }, []);

console.log(groupedArray);
.as-console-wrapper { max-height: 100% !important; top: 0; }

An approach without searching.

const
    data = [{ id: '1', city: 'Sydney', distance: 100, yearhalf: '2022_1' }, { id: '2',city: 'Melbourne', distance: 70, yearhalf: '2022_1' }, { id: '3', city: 'Perth', distance: 65, yearhalf: '2022_1' }, { id: '4', city: 'Sydney', distance: 89, yearhalf: '2022_2' }, { id: '5', city: 'Melbourne', distance: 40,yearhalf: '2022_2' },  { id: '6', city: 'Perth', distance: 40, yearhalf: '2022_2' }, { id: '7', city: 'Sydney', distance: 50, yearhalf: '2022_1' }, { id: '8', city: 'Melbourne', distance: 40, yearhalf: '2022_1' }],
    grouped = Object.values(data.reduce((acc, { city, distance, yearhalf }) => {
        acc[yearhalf] ??= { yearhalf };
        (acc[yearhalf][city] ??= []).push(distance);
        return acc;
    }, []));

console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Sign up to request clarification or add additional context in comments.

3 Comments

It works fine on javascript on the web. But the Nullish Coalescing Operator gives an error on node v14.18.1. I found out it is supported from v15.14.0 onwards. Is there an easy alternative to ??= or should I update node?
you could replace with logical OR, like for this acc[itemIndex][city] ??= [] take acc[itemIndex][city] = acc[itemIndex][city] || []
Thanks a lot for the multi-method approach and clarifying the issue with Nullish Coalescing Operator.
1

const data = [
{id:'1',city:'Sydney',distance:100,yearhalf:'2022_1'},
{id:'2',city:'Melbourne',distance:70,yearhalf:'2022_1'},
{id:'3',city:'Perth',distance:65,yearhalf:'2022_1'},
{id:'4',city:'Sydney',distance:89,yearhalf:'2022_2'},
{id:'5',city:'Melbourne',distance:40,yearhalf:'2022_2'},
{id:'6',city:'Perth',distance:40,yearhalf:'2022_2'},
{id:'7',city:'Sydney',distance:50,yearhalf:'2022_1'},
{id:'8',city:'Melbourne',distance:40,yearhalf:'2022_1'}
]

console.log(Object.values(data.reduce((a,
  {city,distance,yearhalf})=>(((a[yearhalf]??={yearhalf})[city]??=[])
  .push(distance)
,a),{})))

2 Comments

thanks for your answer.It works on web quite fine but I'm getting an error with "Unexpected token '||='" for the Logical OR assignment. Should be okay after updating to Node 15.x. from 14.18 where I'm currently at.
@SKR123 it's possible to rewrite a[b]||=[] as a[b]=a[b]||[], but it detracts from readability, so it's good to upgrade if you can. I also find it hard to read ]||= so ??= is even better

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.