Group array of emails by domain of each email in Javascript

Asked

Viewed 90 times

6

I have an array of emails:

emails = [
  "[email protected]",
  "[email protected]",
  "[email protected]",
  "[email protected]"
]

I am using regular expressions to parse domains, and my intention is to create a JSON with the following structure:

json = {
  "@domain1.com": ["name1", ..., "nameN"],
  ...
  "@domain2.com": ["name1", ..., "nameN"]
}

I’m iterating over every email in the array emails, and when obtaining the domain, I want to check if it already exists in JSON. If so, add the name in the array of this domain and, if not, create a new domain and add the name.

Could someone give me a light on how to do this?

3 answers

6

If I were just to group I could use one reduce but since you need to generate an object with a new structure, I thought I’d go through the items and add to a new element, grouping by domain:

var emails = ["[email protected]",
"[email protected]",
"[email protected]",
"[email protected]"];


var emailAgrupado = {};

emails.forEach(email => {
   // aqui pode usar um regex
   var nome   = email.substring(0, email.lastIndexOf('@'));
   var domain = email.substring(email.lastIndexOf('@'));
    
   // verifica se já existe um elemento com o dominio como chave, senão cria
   if (!emailAgrupado[domain]) {
        emailAgrupado[domain] = [];
    }
    
    // adiciona o nome ao dominio
    emailAgrupado[domain].push(nome);

});

console.log(emailAgrupado);

5

An option is to iterate over each element of the original array, divide the element (which is a string) by the character @ and insert in a dictionary of arrays according to the domain. Note that it is not necessary to use regular expressions to divide each email.

The logic for creating this dictionary is simple:

  • If the domain in question has not yet been registered, it is assigned a new array, filled with the first element already registered.
  • Otherwise (inferring that the domain has already been registered and already infers an array), the email is inserted in the existing list.

This is a very common technique. If you want some other similar examples, see here.

function groupByDomain(emailList) {
  const map = {};
  
  for (const email of emailList) {
    // Dividimos o e-mail pelo caractere `@`:
    const [user, domain] = email.split('@');
    const atDomain = '@' + domain;
    
    if (!map[atDomain]) {
      // Caso nenhum e-mail do domínio atual já tiver sido registrado,
      // inserimos um array com o e-mail atual já preenchido.
      map[atDomain] = [user];
    } else {
      // Se o domínio atual já tiver sido registrado, simplesmente
      // adiciona-se um novo e-mail à lista.
      map[atDomain].push(user);
    }
  }
  
  return map;
}

console.log(
  groupByDomain([
    '[email protected]',
    '[email protected]',
    '[email protected]',
    '[email protected]',
  ])
);

And, as suggested by another answer, could be done with reduce also. The logic is the same - see how it would look:

function groupByDomain(emailList) {
  return emailList.reduce((map, email) => {
    const [user, domain] = email.split('@');
    const atDomain = '@' + domain;

    if (!map[atDomain]) {
      map[atDomain] = [user];
    } else {
      map[atDomain].push(user);
    }

    return map;
  }, {});
}

console.log(
  groupByDomain([
    '[email protected]',
    '[email protected]',
    '[email protected]',
    '[email protected]'
  ])
);

  • 1

    +1 No benchmark this time? :)

  • @Cmtecardeal, not today; because the solutions presented seem to have the same complexity. Disregarding the substring of the other reply and the split of mine, O(n). :-)

4


You can use the function reduce to iterate on the array and assemble the object with the groups:

const emails = [
  "[email protected]",
  "[email protected]",
  "[email protected]",
  "[email protected]"
];

const grupos = emails.reduce((acumulador, email) => {
  const [nome, dominio] = email.split('@');
  const grupo = acumulador[`@${dominio}`] ?? [];
  acumulador[`@${dominio}`] = [...grupo, nome];
  return acumulador;
}, {});

console.log(grupos);


reduce

The method reduce() performs a function reducer (provided by you) for each member of the array, resulting in a single return value.

Example:

const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;

// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
// expected output: 10

// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5));
// expected output: 15

Browser other questions tagged

You are not signed in. Login or sign up in order to post.