0

For instance,

const a = {
  'pt-BR': { food: 'Comida', blue: 'Azul' },
  'en-US': { food: 'Food', blue: 'Blue' },
};

const b = {
  food: { 'pt-BR': 'Comida', 'en-US': 'Food' },
  blue: { 'pt-BR': 'Azul', 'en-US': 'Blue' },
};

Initial solution:

Object.entries(a).forEach(([lang, translations]) => {
  Object.entries(translations).forEach(([word, translation]) => {
    b[word] = { ...b[word], [lang]: translation };
  });
});

Is there a better way to transfrom a into b that hides these forEach loops? Maybe using lodash?

richardaum
  • 6,651
  • 12
  • 48
  • 64
  • 3
    any method that maps to your expected output will iterate each inner entry, it's just whether you see it or not. – pilchard Oct 19 '22 at 21:14
  • I would argue [`for...of`](https://www.google.com/search?q=for...of+mdn&oq=for...of+mdn&sourceid=chrome&ie=UTF-8) loops would be a little more readable, and if you're looking to obscure your nested loops you could stick it all in a [`reduce()`](https://www.google.com/search?q=array.reduce+mdn&sourceid=chrome&ie=UTF-8) but otherwise... – pilchard Oct 19 '22 at 21:32
  • This is basically "transposing" the data, techniques for which are found in many places, including [Transpose data in array of objects](https://stackoverflow.com/q/50183690/215552) – Heretic Monkey Oct 19 '22 at 22:59

1 Answers1

1

You can't avoid going through all the objects but you can reduce the number of intermediate objects allocated by using for...of loops instead of Object.entries + .forEach and not spreading the objects:

function transposeTranslations(translationsByLocale) {
  const translationsByWord = {};
  for (const lang of Object.keys(translationsByLocale)) {
    for (const word of Object.keys(translationsByLocale[lang])) {
      translationsByWord[word] ??= {};
      translationsByWord[word][lang] = translationsByLocale[lang][word];
    }
  }
  return translationsByWord;
}
Valentin
  • 10,769
  • 2
  • 17
  • 27