1

I use Redux to store all my products in a list. Displayed thist list looks like:

[
  {
    "id": 1,
    "name": "BLACK TEA",
    "supplieruuid": "SLIGRO",
  },
  {
    "id": 2,
    "name": "GREEN TEA",
    "supplieruuid": "SLIGRO",
  },
  {
    "id": 3,
    "name": "PURPLE TEA",
    "supplieruuid": "BUNZL",
  },
  {
    "id": 4,
    "name": "RAINBOW TEA",
    "supplieruuid": "BUNZL",
  },
] 

I'm using this reduce function to group these products together by key supplieruuid.

export const selectSortedItems = (state) => state.entities.cart.list.reduce((hash, { ["supplieruuid"]: value, ...rest }) => ({ ...hash, [value]: (hash[value] || []).concat({ ...rest }) }), {});

This returns this array of the products grouped by the key supplieruuid.

[
    {
        "SLIGRO": [
        {
            "id": 1,
            "name": "BLACK TEA",
            "supplieruuid": "SLIGRO",
        },
        {
            "id": 2,
            "name": "GREEN TEA",
            "supplieruuid": "SLIGRO",
        },
        ],
        "BUNZL": [
        {
            "id": 3,
            "name": "PURPLE TEA",
            "supplieruuid": "BUNZL",
        },
        {
            "id": 4,
            "name": "RAINBOW TEA",
            "supplieruuid": "BUNZL",
        },
        ],
    },
] 

except I need this returned as following:

 [
    {
        title: "SLIGRO",
        data: [
        {
            "id": 1,
            "name": "BLACK TEA",
        },
        {
            "id": 2,
            "name": "GREEN TEA",
        },
        ],
    },
    {
        title: "BUNZL",
        data: [
        {
            "id": 3,
            "name": "PURPLE TEA",
        },
        {
            "id": 4,
            "name": "RAINBOW TEA",
        },
        ],
    },
] 

How can I modify the reduce function to display the array as above? With the title and data added.

3
  • 2
    How an object contains 2 properties with the same names title and data in your expected result. You can't achieve this. Commented Jun 2, 2021 at 10:47
  • So sorry, I just updated what I meant. I forgot to close the object. Commented Jun 2, 2021 at 10:52
  • Is this your answer? Commented Jun 2, 2021 at 10:54

3 Answers 3

2

You could take a grouping with an object and a destructuring with unwanted properties for the data. At the end take only the values from the object.

const
    data = [{ id: 1, name: "BLACK TEA", supplieruuid: "SLIGRO" }, { id: 2, name: "GREEN TEA", supplieruuid: "SLIGRO" }, { id: 3, name: "PURPLE TEA", supplieruuid: "BUNZL" }, { id: 4, name: "RAINBOW TEA", supplieruuid: "BUNZL" }],
    result = Object.values(data.reduce((r, { supplieruuid: title, ...o }) => {
        (r[title] ??= { title, data: [] }).data.push(o);
        return r;
    }, {}));

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

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

Comments

0

As you are using reduce, and you need to pass an empty [] as an accumulator.

Second, you need to search for the element if it exists in acc array or not. If it exists then you push the object in the acc else add a new object with 2 property title and data.

const arr = [
  {
    id: 1,
    name: "BLACK TEA",
    supplieruuid: "SLIGRO",
  },
  {
    id: 2,
    name: "GREEN TEA",
    supplieruuid: "SLIGRO",
  },
  {
    id: 3,
    name: "PURPLE TEA",
    supplieruuid: "BUNZL",
  },
  {
    id: 4,
    name: "RAINBOW TEA",
    supplieruuid: "BUNZL",
  },
];

const result = arr.reduce((acc, curr) => {
  const { supplieruuid } = curr;
  const objInAcc = acc.find((o) => o.title === supplieruuid);
  if (objInAcc) objInAcc.data.push(curr);
  else acc.push({ title: supplieruuid, data: [curr] });
  return acc;
}, []);

console.log(result);

Comments

0

Keeping your selectSortedItems like it is, we could create another function to map it as you wish.

const selectSortedItems = (state) => {
  const sortedBySupplierUUID = state.entities.cart.list.reduce((hash, { ["supplieruuid"]: value, ...rest }) => ({ ...hash, [value]: (hash[value] || []).concat({ ...rest }) }), {});
  return Object.keys(selectSortedItems(sortedBySupplierUUID)).map(key => ({ title: key, data: sortedBySupplierUUID[key] }))};
}

3 Comments

Thank you for your reply, since I use the const selectSortedItems inside a useSelector function I get the error 'You must pass a selector to useSelector';
Yes, sorry @Wolf, I forget to add your whole state selector (state.entities.cart.list) since I tested locally. I updated the answer, let me know if it works.
You are awesome! Thanks for you help. It worked!

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.