Home > database >  How to merge two array of object
How to merge two array of object

Time:11-27

enter image description here

array1 =

[
  {
    "name": {
      "common": "Afghanistan",
      "official": "Islamic Republic of Afghanistan",
    "capital": [
      "Kabul"
    ]
  }
]

array2 =

[
"capital": [
          "Kabul"
        ],
"population": 2837743
]

I want to make it

 [
 {
    "name": {
      "common": "Afghanistan",
      "official": "Islamic Republic of Afghanistan",
    "capital": [
      "Kabul"
    ],
    "population": 2837743
  }
]

I want to merge to an array of objects and make one array.i was try to make it with filter method and find method but can't not solve the problem

CodePudding user response:

There are a few issues with trying to do this because you will need a way of handling the merge from a semantic perspective. You need to choose what fields the merge will match on. For example, if two countries have the same population you don't want them to be matched and then merged.

You also need to be aware of and plan for the occurrence of more than two items matching. One problem that immediately comes to mind is if the two objects match yet have conflicting information. This could happen even if they genuinely are a match. Populations change over time. Even things as rigid as the capital changes.

Algorithmically there are two approaches to the matching that I will suggest. The simpler of the two is to have a list of possible fields you want to match the objects on. You can then create an array (Dictionary or hashmap in other languages) that you key by the value seen so far.

var capital_map = []
for(country in countries1   countries2){
 if (capital_map[country.capital]){
   //We have a match that we can then handle
 }else{
  //set up for possible matches down the array
  capital_map[country.capital] = country
}

In the above example, we are only matching on the capital. You could expand this such that if any one of many fields is matched then we merge the two elements or that at least n of N fields match.

The other way I was going to suggest is to create a function that defines some weighted matching. For example, what fraction of the fields that overlap are the same, with each field weighted based on the importance, so the population would be of low importance but capital might be of high importance.

I don't know if you want to go deeper in the nesting of the matching of the two arrays, for example with name vs an official name, but I hope you at least have a better idea of the sorts of techniques you could use for that. You might have had the array of capitals because you expect issues with entities that pass matching but have overlapping fields and didn't want to worry about a resolution. (Such as just taking the average for the population) If you do intend to expand this to more than two sources of data, more than two arrays you can do things like have voting where each source votes for its answer. If two sources say the capital is Brazilia and only one of the three says Rio then you can go with Brazilia.

CodePudding user response:

You can do something like this (I left capital as an array, but it would be simpler if it were not):

const arr1 = [
  {
    name: {
      common: 'Afghanistan',
      official: 'Islamic Republic of Afghanistan',
    },
    capital: ['Kabul'],
  },
  {
    name: {
      common: 'Albania',
      official: 'Republic of Albania',
    },
    capital: ['Tirana'],
  },
];

const arr2 = [
  { capital: ['Tirana'], population: 2845955 },
  { capital: ['Kabul'], population: 2837743 },
];

const populationByCapital = new Map();

for (let el of arr2) {
  populationByCapital.set(el.capital[0], el.population);
}

const arr3 = arr1.map((el) => {
  return { ...el, population: populationByCapital.get(el.capital[0]) };
});

console.log(arr3);

this should give you:

[
  {
    name: {
      common: 'Afghanistan',
      official: 'Islamic Republic of Afghanistan'
    },
    capital: [ 'Kabul' ],
    population: 2837743
  },
  {
    name: { common: 'Albania', official: 'Republic of Albania' },
    capital: [ 'Tirana' ],
    population: 2845955
  }
]

Note that it might break if there are two countries with the same capital names.


Edit

I see now that you were using the API from restcountries.com, thus changing capital to a scalar is beyound your control. And there's a reason why it's an array -- South Africa has 3 capitals. The code should still work because it's the same API, and all 3 are listed in the same order in both endpoints.

But there are couple of complications. The country of Bouvet Island has apparently no capital, and so the array will be empty, and the country of Norfolk Island, and Jamaica have both "Kingston" as the capital. To address both of these issues you can change the key to include the name of the country together with the capital:

const populationByCapital = new Map();

for (let el of arr2) {
  populationByCapital.set(el.capital[0]   el.name.common, el.population);
}

const arr3 = arr1.map((el) => {
  return {
    ...el,
    population: populationByCapital.get(el.capital[0]   el.name.common),
  };
});

CodePudding user response:

I modified your starting data to fix some syntax errors:

const array1 = [
    {
        name: {
            common: 'Afghanistan',
            official: 'Islamic Republic of Afghanistan',
        },
        capital: ['Kabul'],
    },
];

const array2 = [
    {
        capital: ['Kabul'],
        population: 2837743,
    },
];

As requested, this merge uses the filter method to match the two objects:

const newArray = array1.map((arr1Obj) => {
    const capitalObj = array2.filter(
        (arr2Obj) =>
            JSON.stringify(arr1Obj.capital) === JSON.stringify(arr2Obj.capital)
    );

    return Object.assign(arr1Obj, ...capitalObj);
});

console.log(newArray);

Output:

[
    {
        name: {
        common: 'Afghanistan',
        official: 'Islamic Republic of Afghanistan',
        },
        capital: ['Kabul'],
        population: 2837743,
    },
];

CodePudding user response:

First process the data of array2 and build any object with key as capitol and value as object. Use map and array1 and add the corresponding capitol info from process data (track2)

const array1 = [
  {
    name: {
      common: "Afghanistan",
      official: "Islamic Republic of Afghanistan",
    },
    capital: ["Kabul"],
  },
];

const array2 = [
  {
    capital: ["Kabul"],
    population: 2837743,
  },
];

const track2 = {};
array2.forEach(({ capital: [city], ...rest }) => (track2[city] = rest));

const result = array1.map((item) => ({
  ...item,
  ...track2[item.capital?.[0]],
}));

console.log(result)
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related