Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

307
Visualizações
Using reduce, how to make an object directory where every key is a unique value and stores repeated values as sub-objects?

How do I create a function using reduce which will take in an array of objects and return an object directory with unique keys, but allowing for repeated values?

  1. each key is the name of the person
  2. each repeated key has a nested array with a directory of numbers
  3. if there are no repeated keys, the key should holds only one object

I would like the output to look like this:

{
  Bob: {
    '0': { name: 'Bob', age: 30, voted: true },
    '1': { name: 'Bob', age: 31, voted: true },
    '2': { name: 'Bob', age: 32, voted: true },
       },
  Jake: {
    '0': { name: 'Jake', age: 20, voted: false },
    '1': { name: 'Jake', age: 32, voted: true }
       },
  Phil: { name: 'Phil', age: 21, voted: true },
  Ed: { name: 'Ed', age: 55, voted: true },
  Tami: { name: 'Tami', age: 54, voted: true },
  Mary: { name: 'Mary', age: 31, voted: false },
  Becky: { name: 'Becky', age: 43, voted: false },
  Joey: { name: 'Joey', age: 41, voted: true },
  Jeff: { name: 'Jeff', age: 30, voted: true },
  Zack: { name: 'Zack', age: 19, voted: false }
}

This is my code, the results eat one another if two repeated names happen, and it spreads the first object into the key without adding a number key to it.

let count = 0
const toNamedObj = (arr) => {
  return arr.reduce((acc, cur) => {
    let key = Object.values(cur)[0]
    if(acc.hasOwnProperty(key)){
      count ++
      console.log(count)
      return {[key]: {...acc[key], [count]: cur} }
    }
    return {...acc, [key]: cur}
  } ,{})
}

const voters = [
  {name:'Bob' , age: 30, voted: true},
  {name:'Bob' , age: 31, voted: true},
  {name:'Bob' , age: 32, voted: true},
  {name:'Jake' , age: 32, voted: true},
  {name:'Kate' , age: 25, voted: false},
  {name:'Jake' , age: 20, voted: false},
  {name:'Phil' , age: 21, voted: true},
  {name:'Ed' , age:55, voted:true},
  {name:'Tami' , age: 54, voted:true},
  {name: 'Mary', age: 31, voted: false},
  {name: 'Becky', age: 43, voted: false},
  {name: 'Joey', age: 41, voted: true},
  {name: 'Jeff', age: 30, voted: true},
  {name: 'Zack', age: 19, voted: false}
];
console.log(toNamedObj(voters)); 

about 4 years ago · Juan Pablo Isaza
2 Respostas
Responde à pergunta

0

Using your current approach, you'd have to be able to detect, when iterating, if the name already exists, if the object nested in it is a plain voter object (in which case it'd have to be removed and replaced with the array-like object), or if it's the array-like object. While that'd be possible, it'd be convoluted. A better approach would be to unconditionally group into arrays indexed by name, and then transform each array into either the single voter object, or into the {0: .. 1: } object afterwards.

const toNamedObj = (arr) => {
  const votersByName = {};
  for (const voter of voters) {
    votersByName[voter.name] ??= [];
    votersByName[voter.name].push(voter);
  }
  for (const [name, voters] of Object.entries(votersByName)) {
    votersByName[name] = voters.length === 1
      ? voters[0]
      : { ...voters };
  }
  return votersByName;
}

const voters = [
  {name:'Bob' , age: 30, voted: true},
  {name:'Bob' , age: 31, voted: true},
  {name:'Bob' , age: 32, voted: true},
  {name:'Jake' , age: 32, voted: true},
  {name:'Kate' , age: 25, voted: false},
  {name:'Jake' , age: 20, voted: false},
  {name:'Phil' , age: 21, voted: true},
  {name:'Ed' , age:55, voted:true},
  {name:'Tami' , age: 54, voted:true},
  {name: 'Mary', age: 31, voted: false},
  {name: 'Becky', age: 43, voted: false},
  {name: 'Joey', age: 41, voted: true},
  {name: 'Jeff', age: 30, voted: true},
  {name: 'Zack', age: 19, voted: false}
];
console.log(toNamedObj(voters));

Or by mapping the entries

const toNamedObj = (arr) => {
  const votersByName = {};
  for (const voter of voters) {
    votersByName[voter.name] ??= [];
    votersByName[voter.name].push(voter);
  }
  return Object.fromEntries(
    Object.entries(votersByName)
      .map(([name, voters]) => ([
        name,
        voters.length === 1 ? voters[0] : { ...voters }
      ]))
  );
}

const voters = [
  {name:'Bob' , age: 30, voted: true},
  {name:'Bob' , age: 31, voted: true},
  {name:'Bob' , age: 32, voted: true},
  {name:'Jake' , age: 32, voted: true},
  {name:'Kate' , age: 25, voted: false},
  {name:'Jake' , age: 20, voted: false},
  {name:'Phil' , age: 21, voted: true},
  {name:'Ed' , age:55, voted:true},
  {name:'Tami' , age: 54, voted:true},
  {name: 'Mary', age: 31, voted: false},
  {name: 'Becky', age: 43, voted: false},
  {name: 'Joey', age: 41, voted: true},
  {name: 'Jeff', age: 30, voted: true},
  {name: 'Zack', age: 19, voted: false}
];
console.log(toNamedObj(voters));

I recommend against using .reduce when the accumulator is the same value on each iteration - a plain for loop is simpler to write and understand.

about 4 years ago · Juan Pablo Isaza Relatório

0

Presented below is one possible way to achieve the desired objective.

Code Snippet

// method to transform arr to desired format
const toNamedObj = arr => (
  arr.reduce(
    (acc, {name, voted, ...rest}, idx) => (
      (acc[name] ??= []).push({ name, voted, ...rest }),
      (idx === arr.length - 1 && Object.entries(acc).forEach(
          ([k, v]) => (acc[k] = (v.length === 1) ? v[0] : {...v})
      )),
      acc
    ),
    {}
  )
);
/* with explanation
// method to transform arr to desired format
const toNamedObj = arr => (
  // iterate using ".reduce()"
  arr.reduce(
    (acc, {name, voted, ...rest}, idx) => {
      // if "name" not present in "acc", set it as empty array
      acc[name] ??= [];
      // push elt into array
      acc[name].push({ name, voted, ...rest });
      // when iterating over the last item, special processing
      if (idx === arr.length - 1) {    // processed last elt in arr
        // review each value in "acc" and convert to object
        Object.entries(acc)
        .forEach(([k, v]) => {
          if (v.length === 1) {       // only one elt in value-array
            // place the elt as-is
            acc[k] = v[0];
          } else {                    // multiple elts in val-arr
            // convert val-arr to object
            acc[k] = {...v};
          }
        });
      };
      // always return the accumulator "acc" in ".reduce()" callback
      return acc;
    },
    {}        // "acc" is set as an empty object initially
  )
);
*/

const voters = [
  {name:'Bob' , age: 30, voted: true},
  {name:'Bob' , age: 31, voted: true},
  {name:'Bob' , age: 32, voted: true},
  {name:'Jake' , age: 32, voted: true},
  {name:'Kate' , age: 25, voted: false},
  {name:'Jake' , age: 20, voted: false},
  {name:'Phil' , age: 21, voted: true},
  {name:'Ed' , age:55, voted:true},
  {name:'Tami' , age: 54, voted:true},
  {name: 'Mary', age: 31, voted: false},
  {name: 'Becky', age: 43, voted: false},
  {name: 'Joey', age: 41, voted: true},
  {name: 'Jeff', age: 30, voted: true},
  {name: 'Zack', age: 19, voted: false}
];
console.log(toNamedObj(voters));
.as-console-wrapper { max-height: 100% !important; top: 0 }

Explanation

Inline comments added to the snippet above.

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda