traha
traha

Reputation: 13

How to sum properties of elements in an object-array?

I have this array, and I want to sum property (y) of the array elements when x matches certain criteria. For example, if "x" has the same string value between "/" and "?" as another object then add their "y" property together.

const data = [
    {
        "x": "/shop.html",
        "y": 3
    },
    {
        "x": "/",
        "y": 2
    },
    {
        "x": "/?test324",
        "y": 1
    },
    {
        "x": "/account.html",
        "y": 1
    },
    {
        "x": "/account.html?test1",
        "y": 1
    },
    {
        "x": "/shop.html?test543",
        "y": 1
    }
]

And it should be like this at the end

    const expectedResult = [
        {
            "x": "/shop.html",
            "y": 4
        },
        {
            "x": "/",
            "y": 3
        },
        {
            "x": "/account.html",
            "y": 2
        },
       
    ]

So as you can see the 2nd array doesn't have the "?xxx" thing, they are all "merged" based on string value between last "/" and "?"

Tried to do something like this

let output = res.data.data.reduce(function (accumulator, cur) {
                    let x = cur.x,
                        found = accumulator.find(function (elem) {
                            elem.x = elem.x.split("?")[0];
                            return elem.x == x;
                        });
                    if (found) found.y += cur.y;
                    else accumulator.push(cur);
                    return accumulator;
                }, []);

But duplicated values doesn't add themselves.

It returns me this

[
    {
        "x": "/shop.html",
        "y": 3
    },
    {
        "x": "/",
        "y": 2
    },
    {
        "x": "/",
        "y": 1
    },
    {
        "x": "/account.html",
        "y": 1
    },
    {
        "x": "/account.html",
        "y": 1
    },
    {
        "x": "/shop.html?test543",
        "y": 1
    }
]

Any idea?

Upvotes: 0

Views: 697

Answers (1)

jsN00b
jsN00b

Reputation: 3691

The below may be one possible solution to achieve the desired objective.

Code Snippet

// a small helper method to convert key by leaving out the z-s in: '/xxxx?zzz'
const convertKey = x => (x.split('?')[0]);

// use reduce to iterate thru the array & obtain a result-object
// destructure to get 'x', 'y'
// if 'x' already present, add 'y'
// else create an object with 'x', 'y' props
// return the `Object.values` of the result-object
const transform = arr => (
  Object.values(
    arr.reduce(
      (acc, {x, y}) => ({
        ...acc,
        [convertKey(x)]: {
          ...(acc[convertKey(x)] || {x}),
          y: (acc[convertKey(x)]?.y || 0) + y
        }
      }),
      {}
    )
  )
);

const data = [
    {
        "x": "/shop.html",
        "y": 3
    },
    {
        "x": "/",
        "y": 2
    },
    {
        "x": "/?test324",
        "y": 1
    },
    {
        "x": "/account.html",
        "y": 1
    },
    {
        "x": "/account.html?test1",
        "y": 1
    },
    {
        "x": "/shop.html?test543",
        "y": 1
    }
];

console.log(transform(data));

Explanation

The above code-snippet has inline comments describing the steps. For further description, please post specific questions on comments below, if required.

Upvotes: 1

Related Questions