0

I have an array of objects containing world countries with some additional information e.g.

countries = [
  {
    flag: 'assets/flags/angola.svg',
    code: 'AGO',
    name: 'Angola',
    regions: [{
      name: 'Luanda'
    }]
  },
  {
    flag: 'assets/flags/albania.svg',
    code: 'ALB',
    name: 'Albania',
    regions: [{
      name: 'Korça'
    }, {
      name: 'Tirana'
    }, {
      name: 'Gjirokastër'
    }]
  }...

I want to extract three of my favorite countries into a new array while removing them from the original array so I end up with two arrays one for my favorite countries and one for the rest of the countries.

I managed to achieve this the following way:

public createCountriesList(allCountries: Country[]) {

let topCountries: Country[] = [];
let restOfCountries: Country[];

allCountries.forEach((element) => {
  switch (element.code) {
    case 'HRV':
      topCountries.push(element);
      break;
    case 'AT':
      topCountries.push(element);
      break;
    case 'GER':
      topCountries.push(element);
      break;
  }
});

restOfCountries = allCountries.filter((c) => {
  return !topCountries.includes(c);
});}

It works, but I was wondering if there is a more elegant way to do this?

3
  • 3
    Code that already works has a best fit on CodeReview Commented Mar 16, 2022 at 22:04
  • 1
    Tip: You can combine case clauses to have them execute the same block. See examples Commented Mar 16, 2022 at 22:08
  • I will keep that in mind next time @Christina Commented Mar 16, 2022 at 23:14

4 Answers 4

3

Everything seems fine according to me... Obviously you need two arrays one for the extracted ones and second for rest of countries.

One thing we can work on is the switch case.

Instead of switch case you can use .includes function. Store the name of countries you want to extract in an array.

const arr = ['HRV','AT','GR']

now you can do,

if(arr.includes(element.code)){
//push into new array
} else{
//push into another 
}

One more thing you can do is save restOfTheCountries using .filter function. Just return true for the countries which fails your above if case.

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

Comments

1

You can just use regular filter to split the array:

const isTop = ({code}) => ['HRV','AT','GR'].includes(code);
const topCountries = allCountries.filter(isTop);
const restOfCountries = allCountries.filter((contry) => !isTop(contry));

Another way, you can add a property that shows whether this country is top or not, and filter by this key

const withTop = countries.map((e) => ({...e, top: ['AGO','AT','GR'].includes(e.code)}));

// {
//   code: "AGO"
//   flag: "assets/flags/angola.svg"
//   name: "Angola"
//   regions: [{…}]
//   top: true
// }

Comments

1

I would probably create a separate generic function for splitting array based on the criteria (using ts since you are)

const splitArray = <T>(array: Array<T>, matchFunction: (el: T) => boolean) => {
  const matching: T[] = [], nonMatching: T[] = []
  array.forEach(el => matchFunction(el) ? matching.push(el) : nonMatching.push(el))
  return [matching, nonMatching]
}

then you can call it with the array and a function

const [topCountries, restOfCountries] = splitArray(countries, c => ["HRV", "AT", "GER"].includes(c.code))

that would be a bit more readable. a more elegant solution is to extend Array with that functionality (Array.prototype.split) then using countries.split(c => ["HRV", "AT", "GER"].includes(c.code))

Comments

-1

All suggestions so far seem valid, I ended up using @Alexandr Belan answer as it was the most straightforward to implement in my case, I don't know why I used switch case instead of filter like for the topCountries 🤷‍♂️. Final code (added alphabetical sorting of the countries as well)

  const suggestedCountriesList = ['Brazil', 'France', 'Germany'];
    const suggested = ({ name }) => suggestedCountriesList.includes(name);
    const suggestedCountries = allCountries.filter(suggested);
    const otherCountries = allCountries.filter((country) => !suggested(country));

// sort alphabetically
    otherCountries.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));
    suggestedCountries.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));


    return [suggestedCountries, otherCountries];

1 Comment

This is not an answer.

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.