mfaccord
mfaccord

Reputation: 225

How to reduce array of objects into one object?

I'm beginning working with reduce and I'm having a hard time conceptualizing how to use it. I understand it when using numbers, but when it comes to objects and other data, I have a hard time following the logic. I want to take an array of objects and return an object with the keys of countryName and the value being an object with the rest of the country data. Any help would be greatly appreciated!

Data

var countries = [
  {
    "countryCode": "AF",
    "countryName": "Afghanistan",
    "population": "29121286",
    "capital": "Kabul",
    "continentName": "Asia"
  },
  {
    "countryCode": "AL",
    "countryName": "Albania",
    "population": "2986952",
    "capital": "Tirana",
    "continentName": "Europe"
  },
  {
    "countryCode": "DZ",
    "countryName": "Algeria",
    "population": "34586184",
    "capital": "Algiers",
    "continentName": "Africa"
  },
]

Expected Output

{
  Afghanistan: {
    "countryCode": "AF",
    "population": "29121286",
    "capital": "Kabul",
    "continentName": "Asia"
  },
  Albania: {
    "countryCode": "AL",
    "population": "2986952",
    "capital": "Tirana",
    "continentName": "Europe"
  },
  Algeria: {
    "countryCode": "DZ",
    "population": "34586184",
    "capital": "Algiers",
    "continentName": "Africa"
  },
}

Base Attempt

function organizeByCountry(countries) {
  return countries.reduce((acc, country) => {

    return country.countryName 
  }, {})
}

Upvotes: 3

Views: 16121

Answers (3)

gabs97
gabs97

Reputation: 31

let countries = [
    {
      "countryCode": "AF",
      "countryName": "Afghanistan",
      "population": "29121286",
      "capital": "Kabul",
      "continentName": "Asia"
    },
    {
      "countryCode": "AL",
      "countryName": "Albania",
      "population": "2986952",
      "capital": "Tirana",
      "continentName": "Europe"
    },
    {
      "countryCode": "DZ",
      "countryName": "Algeria",
      "population": "34586184",
      "capital": "Algiers",
      "continentName": "Africa"
    },]


const countryName = countries.reduce((acc, country)=>{
        return {...acc, [country.countryName]:country}
    },{})
    
 console.log(countryName)

Upvotes: 3

hexbioc
hexbioc

Reputation: 1606

Array.prototype.reduce in its typical usage can be visualized as a function that progressively builds your output one list entry at a time, starting with the first list entry and the accumulator you provide as the second argument (In this case, {}).

reduce invokes your callback for every list item (Except when you don't pass an accumulator, you can read more on this on MDN). In the first invocation in your case, the callback receives arguments as below:

acc = {};
country = {
  countryCode: "AF",
  countryName: "Afghanistan",
  population: "29121286",
  capital: "Kabul",
  continentName: "Asia"
};

We now start building the result. We want an object which has keys as the country names and values as the rest of the attributes in the object. We build exactly that, by modifying the accumulator:

acc[country.countryName] = {
  countryCode: country.countryCode,
  population: country.population,
  capital: country.capital,
  continentName: country.continentName
};

We then return this modified accumulator from the callback. In the next invocation of the callback by reduce, the callback receives this previously returned accumulator as the acc argument and the second list item as country:

acc = {
  Afghanistan: {
    countryCode: "AF",
    population: "29121286",
    capital: "Kabul",
    continentName: "Asia"
  }
};
country = {
  countryCode: "AL",
  countryName: "Albania",
  population: "2986952",
  capital: "Tirana",
  continentName: "Europe"
};

At this point, we repeat and return the modified accumulator. After reduce invokes the callback for the last time with the updated accumulator and the last item from the list, the value returned by the callback is returned by the reduce function itself. We thus have our output now, using reduce.


The above logic can be concisely implemented as below, while additionally avoiding mutations:

function organizeByCountry(countries) {
  return countries.reduce((acc, country) => {
    const {countryName, ...rest} = country;

    return {...acc, [countryName]: rest};
  }, {});
};

Upvotes: 10

Ori Drori
Ori Drori

Reputation: 191946

You can use Array.map() to create an array of [country, object] pairs, and convert it to an object using Object.fromEntries():

const keyByWithoutKey = (arr, key) => Object.fromEntries(
  arr.map(({ [key]: prop, ...o }) => [prop, o])
)

const countries =  [{"countryCode":"AF","countryName":"Afghanistan","population":"29121286","capital":"Kabul","continentName":"Asia"},{"countryCode":"AL","countryName":"Albania","population":"2986952","capital":"Tirana","continentName":"Europe"},{"countryCode":"DZ","countryName":"Algeria","population":"34586184","capital":"Algiers","continentName":"Africa"}]

const result = keyByWithoutKey(countries, 'countryName')

console.log(result)

Upvotes: 2

Related Questions