marcus petty
marcus petty

Reputation: 69

Mapping rows of a table to values of an object without repeating myself

I have a data array that is made up of two objects. I need to loop through the data array and put the values of the same key on the same row. For example all key's = 'a' need to go on the same row but on a different column. How can I achieve this without repeating myself as I have done in the examples below?

Here is my data structure

const data = [{a:1. b:2, c:3, d:3},{a:2, b:5, c:1, d:5}] 
<table className="table study">
        <tbody>
          <tr>
            <th></th>
            {data.map((item, key) =>  <th key={key}>{item.a}
            </th>
            )}
          </tr>  
          <tr>
            <td>Title A</td>
            {data.map((item, key) => (
              <td key={key}>{item.a}</td>
            ))}
          </tr>
          <tr>
            <td>Title B</td>
            {data.map((item, key) => (
              <td key={key}>{item.b}</td>
            ))}
          </tr>
          <tr>
            <td>Title C</td>
            {data.map((item, key) =>  <td key={key}>{item.c}
            </td>)}
          </tr>

        </tbody>
      </table>

Upvotes: 0

Views: 500

Answers (2)

ed&#39;
ed&#39;

Reputation: 1895

You can flatten the data before using it.

I find its easier to modify data into a usable shape when I run into problems like this.

// Can have different keys across objects (if you want)
const rawData = [
  { a: 1, b: 2, c: 3, d: 3 },
  { a: 2, b: 5, c: 1, d: 5 },
  { e: 2, f: 5, c: 1, d: 5 },
  { b: 5, c: 1, e: 5 },
];

// Flattens to { key: [...values] }
const flattenedData = rawData.reduce((acc, curr) => {
  for (const key in curr) {
    if (!curr.hasOwnProperty(key)) {
      continue;
    }

    if (!acc[key]) {
      acc[key] = [];
    }

    acc[key].push(curr[key]);
  }

  return acc;
}, {});

const Table = ({ data }) => (
  <table className="table study">
    <tbody>
      {Object.keys(data).map(rowKey => (
        <tr key={rowKey}>
          <th>Title {rowKey.toUpperCase()}</th>
          {data[rowKey].map((item, cellKey) => (
            <td key={cellKey}>{item}</td>
          ))}
        </tr>
      ))}
    </tbody>
  </table>
);

ReactDOM.render(<Table data={flattenedData} />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="root"></div>

Upvotes: 0

Brooks Lybrand
Brooks Lybrand

Reputation: 91

I believe you want something along these lines:

const data = [{ a: 1, b: 2, c: 3, d: 3 }, { a: 2, b: 5, c: 1, d: 5 }];
<table className="table study">
  <tbody>
    <tr>
      <th />
      {data.map((item, key) => <th key={key}>{item.a}</th>)}
    </tr>
    {Object.keys(data[0]).map(key => {
      return (
        <tr>
          <td>Title {key.toUpperCase()}</td>
          {data.map((item, idx) => <td key={key+idx}>{item[key]}</td>)}
        </tr>
      );
    })}
  </tbody>
</table>

Note: this does not make the keys unique, which is a problem since React expects unique keys for it's diffing algorithms to work optimally.

Upvotes: 1

Related Questions