0

I want to display this data in table by country. First I selected all repeated countries in one array and filtered them. Next I map all data to show this in the table but I don't know how to separete this countries after mapping. My goal in this case should be:

  1. Germany
  • Munich pop
  • Berlin pop
  • Dortmund pop
  1. England
  • London pop
  • Liverpool pop
  • Manchester pop

... now I have country name in every row which i don't want Germany Munich pop Germany Berlin pop Germany Dortmund pop

Code:

import React from "react";
import "./styles.css";
import { data } from "./data";

export default function App() {
  let countries = [];
  const mapCountries = data.map((country, index) =>
    countries.push(country.country)
  );
  countries = countries.filter(
    (item, index, aref) => aref.indexOf(item) === index
  );

  const showCity = data.map((item, index) => (
    <>
    <tr>
      <td colspan='2'>{item.country}</td>
    </tr>
    <tr>
      <td>{item.city}</td>
      <td>{item.pop}</td>
    </tr>
    </>
  ))
  return (
    <div className="App">
      <table>
        {showCity}
        </table>
    </div>
  );
}

export const data = [
  {
    country: "Spain",
    city: "Madrit",
    pop: 3500000
  },
  {
    country: "Spain",
    city: "Barcelona",
    pop: 1500000
  },
  {
    country: "Spain",
    city: "Valencia",
    pop: 1000000
  },
  {
    country: "Germany",
    city: "Berlin",
    pop: 4500000
  },
  {
    country: "Germany",
    city: "Munich",
    pop: 1500000
  },
  {
    country: "Germany",
    city: "Dortmund",
    pop: 1000000
  },
  {
    country: "England",
    city: "London",
    pop: 8000000
  },
  {
    country: "England",
    city: "Liverpool",
    pop: 500000
  },
  {
    country: "England",
    city: "Manchester",
    pop: 1000000
  }
];

4 Answers 4

1

When grouping data I generally try to use the reduce method. It can be a bit daunting to learn but is very versatile once you get used to it.

The iterator function takes four parameters; an accumulator, the current value, the current index, and the original source array. For grouping data we generally only need the first two though. For each item the function is called, and the return value is passed to the next iteration for the final accumulated value.

The concept is to group by a specific index, preferably an id of sorts (like country name).

const data = [
  {
    country: "Spain",
    city: "Barcelona",
    pop: 1500000
  },
  {
    country: "Spain",
    city: "Valencia",
    pop: 1000000
  },
  {
    country: "Germany",
    city: "Berlin",
    pop: 4500000
  },
];

class App extends React.Component {
  render() {
    const grouped = data.reduce((acc, item) => ({
      // we use the spread operator to add all previous keys
      ...acc,
      // Object.hasOwnProperty checks if the grouping key is present on acc
      [item.country]: Object.hasOwnProperty.call(acc, item.country)
        // if it is we use the existing group and add our item to its list
        ? [...acc[item.country], item]
        // otherwise create a new array with the groups first item
        : [item]
      }),
      // this is the initial value for acc, an empty object
      {});

    // Now the data looks something like
    // {
    //  "Spain": [{ country: "Spain", city: "Barcelona", pop: 1500000 }],
    //  "Germany": [...]
    // }
    // With each country having an array of each item in it.
    // In order to show this in a table you can first iterate each entry
    // in grouped and for each group iterate each city.

    const showCity = Object
      .entries(grouped)
      // we can use the destructuring operator to "unpack" country and its list of cities here
      .map(([country, cities]) => (
        <tbody>
          <tr>
            <td colSpan="2">
              <span>{country}</span>
            </td>
          </tr>
          {cities.map(city => (
            <tr>
              <td>{city.city}</td>
              <td>{city.pop}</td>
            </tr>
          ))}
        </tbody>));

    return (
      <table>
        {showCity}
      </table>
    );
  }
}
ReactDOM.render(
  <App />,
  document.body
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

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

Comments

0

Here is how you can group the data according to country:

const data = [
  {
country: "Spain",
city: "Madrit",
pop: 3500000,
  },
  {
country: "Spain",
city: "Barcelona",
pop: 1500000,
  },
  {
country: "Spain",
city: "Valencia",
pop: 1000000,
  },
  {
country: "Germany",
city: "Berlin",
pop: 4500000,
  },
  {
country: "Germany",
city: "Munich",
pop: 1500000,
  },
  {
country: "Germany",
city: "Dortmund",
pop: 1000000,
  },
  {
country: "England",
city: "London",
pop: 8000000,
  },
  {
country: "England",
city: "Liverpool",
pop: 500000,
  },
  {
country: "England",
city: "Manchester",
pop: 1000000,
  },
];

let sol = {};

for (let country of data) {
  if (sol[country.country] === undefined) {
sol[country.country] = { city: [country.city], pop: [country.pop] };
  } else {
sol[country.country] = {
  city: [...sol[country.country].city, country.city],
  pop: [...sol[country.country].pop, country.pop],
};
  }
}

//console.log(sol);

for (let key of Object.keys(sol)) {
  console.log(key);
  for (let i in sol[key].city) {
console.log(sol[key].city[i], " ", sol[key].pop[i]);
  }
  console.log("------------");
}

Full ReactJS Example based on your question:

import React, { useState } from "react";
import "./styles.css";

export default function App() {
  const [nations, setNations] = useState(getNations(data));

  const showCity = Object.keys(nations).map((item, index) => (
    <>
      <th>
        <td colspan="2">{item}</td>
      </th>

      {nations[item]["city"].map((_, i) => (
        <tr>{nations[item]["city"][i] + ":" + nations[item]["pop"][i]}</tr>
      ))}
    </>
  ));
  return (
    <div className="App">
      <table>{showCity}</table>
    </div>
  );
}

const data = [
  {
    country: "Spain",
    city: "Madrit",
    pop: 3500000
  },
  {
    country: "Spain",
    city: "Barcelona",
    pop: 1500000
  },
  {
    country: "Spain",
    city: "Valencia",
    pop: 1000000
  },
  {
    country: "Germany",
    city: "Berlin",
    pop: 4500000
  },
  {
    country: "Germany",
    city: "Munich",
    pop: 1500000
  },
  {
    country: "Germany",
    city: "Dortmund",
    pop: 1000000
  },
  {
    country: "England",
    city: "London",
    pop: 8000000
  },
  {
    country: "England",
    city: "Liverpool",
    pop: 500000
  },
  {
    country: "England",
    city: "Manchester",
    pop: 1000000
  }
];

const getNations = () => {
  let sol = {};

  for (let country of data) {
    if (sol[country.country] === undefined) {
      sol[country.country] = { city: [country.city], pop: [country.pop] };
    } else {
      sol[country.country] = {
        city: [...sol[country.country].city, country.city],
        pop: [...sol[country.country].pop, country.pop]
      };
    }
  }

  return sol;
};

Screenshot:

Screenshot

Working Example: Codesandbox

As you have a value of all the nations and their cities grouped, you can perform filtering if required very easily.

Comments

0

The simplest solution is to create county cities map and use it anyway in next processing:

const data = [
  {
    country: "Spain",
    city: "Madrit",
    pop: 3500000
  },
  {
    country: "Spain",
    city: "Barcelona",
    pop: 1500000
  },
  {
    country: "Spain",
    city: "Valencia",
    pop: 1000000
  },
  {
    country: "Germany",
    city: "Berlin",
    pop: 4500000
  },
  {
    country: "Germany",
    city: "Munich",
    pop: 1500000
  },
  {
    country: "Germany",
    city: "Dortmund",
    pop: 1000000
  },
  {
    country: "England",
    city: "London",
    pop: 8000000
  },
  {
    country: "England",
    city: "Liverpool",
    pop: 500000
  },
  {
    country: "England",
    city: "Manchester",
    pop: 1000000
  }
];

const createCountryCitiesMap = data => {
  let countries = new Set();
  data.map(item => countries.add(item.country));

  let result = new Map();
  countries.forEach(country => 
  result.set(
    country, 
    data.filter(item => item.country === country).map(item => ({...{}, ...{city: item.city, pop: item.pop}}))
    )
  );

  return result;
};


createCountryCitiesMap(data).forEach((value, key) => console.log(key + JSON.stringify(value)));

Comments

0

You can use group the countries with Array.prototype.reduce() and then use Object.entries() like so:

const groupCountries = Object.entries(
  data.reduce((acc, { country, ...rest }) => {
    if (!acc[country]) {
      acc[country] = [rest];
    } else {
      acc[country] = [...acc[country], rest];
    }

    return acc;
  }, {})
);

and then render it like this:

 const showCity = groupCountries.map(([country, cities], index) => (
    <tbody key={new Date().getTime() + index}>
      <tr>
        <td colSpan="2">{country}</td>
      </tr>
      {cities.map(({ city, pop }) => (
        <tr key={city}>
          <>
            <td>{city}</td>
            <td>{pop}</td>
          </>
        </tr>
      ))}
    </tbody>
  ));

Here is the sand box link:
https://codesandbox.io/s/quirky-https-74ynq?fontsize=14&hidenavigation=1&theme=dark

Array.prototype.reduce
Object.entries()

Comments

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.