1

I'm trying to build a data structure where all elements would be grouped based on an object key.

Everything works fine except that I can't check if the new array has the data duplicated, as it's outside the for..of loop. I'm looking for a way to prevent pushing a further object if the new array already has it.

Current output (note that the list of characters from Japan appear twice)

[
  [
    { "country": "US" },
    [
      { "name": "Guile", "country": "US" }
    ]
  ],
  [
    { "country": "Japan" },
    [
      { "name": "E. Honda", "country": "Japan" },
      { "name": "Ryu", "country": "Japan" }
    ]
  ],
  [
    { "country": "Japan" },
    [
      { "name": "E. Honda", "country": "Japan" },
      { "name": "Ryu", "country": "Japan" }
    ]
  ],
  [
    { "country": "Thailand" },
    [
      { "name": "Sagat", "country": "Thailand" }
    ]
  ]
]

Expected output

[
  [
    { "country": "US" },
    [
      { "name": "Guile", "country": "US" }
    ]
  ],
  [
    { "country": "Japan" },
    [
      { "name": "E. Honda", "country": "Japan" },
      { "name": "Ryu", "country": "Japan" }
    ]
  ],
  [
    { "country": "Thailand" },
    [
      { "name": "Sagat", "country": "Thailand" }
    ]
  ]
]

What I have so far

var data = [
  {name: 'Guile', country: 'US'},
  {name: 'E. Honda', country: 'Japan'},
  {name: 'Ryu', country: 'Japan'},
  {name: 'Sagat', country: 'Thailand'}
]

const getNationList = (streetFighterList) => {
  let filteredList = []
  for (const [index, characterData] of streetFighterList.entries()) {
    // .......................................................
    // looking for ways here to check if `filteredList` already
    // has the data I'm trying to push. Since it's empty
    // I don't know how to check its index. :(
    // NOTE: indexOf() doesn't seem to work
    // .......................................................
    const indexOf = filteredList.indexOf(streetFighterList[index].country)
    if (indexOf == -1) {
      filteredList.push([
        { country: characterData.country },
        streetFighterList.filter((character) => {
          return character.country === characterData.country
        })
      ])
    }
  }
  return filteredList
}

console.log(getNationList(data))

Note: I understand that given the country object is always unique this data structure would be better and easier if I used a string instead. However this is a sample data and in a real life code I do need it stored as an object.

2
  • is this possible to change your object format to { [country]: [names] }? then it is easier to remove duplication and find names belonging to the same country Commented Mar 29, 2019 at 16:47
  • unfortunately not. I need the obj key to be immutable Commented Mar 29, 2019 at 16:51

3 Answers 3

1

I would recommend using some to validate as following

var data = [
  {name: 'Guile', country: 'US'},
  {name: 'E. Honda', country: 'Japan'},
  {name: 'Ryu', country: 'Japan'},
  {name: 'Sagat', country: 'Thailand'}
]

const getNationList = (streetFighterList) => {
  let filteredList = []
  for (const [index, characterData] of streetFighterList.entries()) {

    const entry = filteredList.some(item => item[0].country === streetFighterList[index].country)
    if (!entry) {
      filteredList.push([
        { country: characterData.country },
        streetFighterList.filter((character) => {
          return character.country === characterData.country
        })
      ])
    }
  }
  return filteredList
}

console.log(getNationList(data))
Sign up to request clarification or add additional context in comments.

Comments

1

Reduce the array to object, with the country names as the keys. Combine players that are under the same country to an object, with the player's name as the key.

When done, convert back to an array using Object.values(), and map the array to convert the player's objects to arrays via Object.values() as well.

const data = [[{"country":"US"},[{"name":"Guile","country":"US"}]],[{"country":"Japan"},[{"name":"E. Honda","country":"Japan"},{"name":"Ryu","country":"Japan"}]],[{"country":"Japan"},[{"name":"E. Honda","country":"Japan"},{"name":"Ryu","country":"Japan"}]],[{"country":"Thailand"},[{"name":"Sagat","country":"Thailand"}]]]

const result = Object.values(data.reduce((r, [c, p]) => { 
  if(!r[c.country]) r[c.country] = [c, {}]
  
  const players = r[c.country][1];
  
  p.forEach(o => { if(!players[o.name]) players[o.name] = o; })
  
  return r;
}, {})).map(([c, p]) => [c, Object.values(p)]);

console.log(result)

Comments

1

You could first create a Set of unique countries and then loop through them to combine each one with a list of fighters from that country. For example:

const data = [{ name: 'Guile', country: 'US' }, { name: 'E. Honda', country: 'Japan' }, { name: 'Ryu', country: 'Japan' }, { name: 'Sagat', country: 'Thailand' }];
const countries = new Set(data.map((obj) => obj.country));
const output = [...countries].map((country) => {
  const entries = data.filter((obj) => obj.country === country);
  return [{ country }, entries];
});

console.log(output);
/*
[
  [
    {"country": "US"},
    [{"name": "Guile", "country": "US"}]
  ],
  [
    {"country": "Japan"},
    [{"name": "E. Honda", "country": "Japan"}, {"name": "Ryu", "country": "Japan" }]
  ],
  [
    {"country": "Thailand"},
    [{"name": "Sagat", "country": "Thailand"}]
  ]
]
*/

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.