1

Ok, so I have an array of objects that look like that

{id: 1, color: "red", size: "S", free: 14, location: "Location #1"}
{id: 2, color: "green", size: "M", free: 5, location: "Location #1"}
{id: 3, color: "red", size: "M", free: 3, location: "Location #2"}
{id: 4, color: "green", size: "L", free: 12, location: "Location #1"}
{id: 5, color: "green", size: "S", free: 5, location: "Location #2"}
{id: 6, color: "red", size: "L", free: 0, location: "Location #1"}
{id: 7, color: "blue", size: "L", free: 0, location: "Location #2"}
{id: 8, color: "blue", size: "M", free: 0, location: "Location #1"}
{id: 9, color: "blue", size: "S", free: 0, location: "Location #1"}
{id: 10, color: "purple", size: "L", free: 0, location: "Location #2"}

And I want to be able to generate a table that would look something like that

enter image description here

I suppose that i have to filter or group some of the key-value pairs or something like that but i don't know the right way to approach this.

Again maybe for this particular table I have to do something like this:

{
  color: 'red',
  location: 'Location #1',
  sizes: [
    {
      s: 12
    },
    {
      m: 5
    },
    {
      l: 7
    }
  ]
}

{
  color: 'green',
  location: 'Location #1',
  sizes: [
    {
      s: 3
    },
    {
      m: 11
    },
    {
      l: 4
    }
  ]
}

But then i have to figure out how to populate the HTML table itself with this data. Maybe there is some library or something that would help me do that. Thanks!

2
  • 1
    Break this problem down into smaller parts. Start by researching how to do a groupBy mapping of the array. Then work on iterating that array to create table rows Commented Feb 3, 2019 at 16:56
  • @dellavi98 This question has two sides, try to simplify the question, to make easier to understand. Commented Feb 3, 2019 at 17:40

2 Answers 2

1

See the table generated at the end

You can use reduce to accumulate the sizes for each color and each location. Here is an example way to use reduce and the resulting tree.

const tree = data.reduce((accum, { id, color, size, free, location }) => {
  accum[location] = accum[location] || { };
  accum[location][color] = accum[location][color] || { S: 0, M: 0, L: 0 };
  accum[location][color][size] += free;
  return accum;
}, {});
{
  "Location #1": {
    "red": {
      "S": 14,
      "M": 0,
      "L": 0
    },
    "green": {
      "S": 0,
      "M": 5,
      "L": 12
    },
    "blue": {
      "S": 0,
      "M": 0,
      "L": 0
    }
  },
  "Location #2": {
    "red": {
      "S": 0,
      "M": 3,
      "L": 0
    },
    "green": {
      "S": 5,
      "M": 0,
      "L": 0
    },
    "blue": {
      "S": 0,
      "M": 0,
      "L": 0
    },
    "purple": {
      "S": 0,
      "M": 0,
      "L": 0
    }
  }
}

To create the table, you can iterate over the location entries, and for each location iterate over the colors, then append the rows to the table.

You can create each row by cloning a row template that you query from the DOM, then append that row to your table body:

const data = [  
  {id: 1, color: "red", size: "S", free: 14, location: "Location #1"},
  {id: 2, color: "green", size: "M", free: 5, location: "Location #1"},
  {id: 3, color: "red", size: "M", free: 3, location: "Location #2"},
  {id: 4, color: "green", size: "L", free: 12, location: "Location #1"},
  {id: 5, color: "green", size: "S", free: 5, location: "Location #2"},
  {id: 6, color: "red", size: "L", free: 0, location: "Location #1"},
  {id: 7, color: "blue", size: "L", free: 0, location: "Location #2"},
  {id: 8, color: "blue", size: "M", free: 0, location: "Location #1"},
  {id: 9, color: "blue", size: "S", free: 0, location: "Location #1"},
  {id: 10, color: "purple", size: "L", free: 0, location: "Location #2"}
];

const tree = data.reduce((accum, { id, color, size, free, location }) => {
  accum[location] = accum[location] || { };
  accum[location][color] = accum[location][color] || { S: 0, M: 0, L: 0 };
  accum[location][color][size] += free;
  return accum;
}, {});

const tpl = document.querySelector('#row-template');
const tbody = document.querySelector("tbody");

Object.entries(tree).forEach(([location, values]) => {
  Object.entries(values).forEach(([color, sizes]) => {
    const clone = document.importNode(tpl.content, true);
    const td = clone.querySelectorAll("td");
    td[0].textContent = location;
    td[1].textContent = color;
    td[2].textContent = sizes['S'];
    td[3].textContent = sizes['M'];
    td[4].textContent = sizes['L'];

    tbody.appendChild(clone);
  });
});
table {
  border-collapse: collapse;
}
thead {
  font-weight: bold;
}
td {
  padding: 5px;
  border: 1px solid black;
}
<template id="row-template">
  <tr>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
  </tr>
</template>

<table id="data-table">
  <thead>
    <tr>
      <td>Location</td><td>color</td><td>S</td><td>M</td><td>L</td>
    </tr>
  </thead>
  <tbody>
  </tbody>
</table>

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

1 Comment

Thank you! That worked as a charm. Yours is probably the one that I fully understand what happens.
1

You could build a tree and collect al value you have in your data set. The result is a tree where the keys are the location, color and size values. At the leaves, you get the accumulated value of free.

Then you could build a array for the table with the accumulated values.

function getTable(object) {
    function getRows(object, row = []) {
        if (row.length === 2) {
            table.push(row.concat(['S', 'M', 'L'].map(k => object[k] || 0)));
            return;
        }
        Object.entries(object).forEach(([k, v]) => getRows(v, row.concat(k)));
    }

    var table = [];
    getRows(object);
    return table;
}

var data = [{ id: 1, color: "red", size: "S", free: 14, location: "Location #1" }, { id: 2, color: "green", size: "M", free: 5, location: "Location #1" }, { id: 3, color: "red", size: "M", free: 3, location: "Location #2" }, { id: 4, color: "green", size: "L", free: 12, location: "Location #1" }, { id: 5, color: "green", size: "S", free: 5, location: "Location #2" }, { id: 6, color: "red", size: "L", free: 0, location: "Location #1" }, { id: 7, color: "blue", size: "L", free: 0, location: "Location #2" }, { id: 8, color: "blue", size: "M", free: 0, location: "Location #1" }, { id: 9, color: "blue", size: "S", free: 0, location: "Location #1" }, { id: 10, color: "purple", size: "L", free: 0, location: "Location #2" }],
    tree = data.reduce((r, o) => {
        var q = ['location', 'color'].reduce((p, k) => p[o[k]] = p[o[k]] || {}, r);
        q[o.size] = (q[o.size] || 0) + o.free;
        return r;
    }, {}),
    table = getTable(tree);

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

1 Comment

It’s the most elegant solution but I will have to take my time to fully comprehend what happens. Thank you.

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.