kurtko
kurtko

Reputation: 2126

JS apply function to all values of object

I have an object like this:

const player = {
  id: 123,
  country: 'GB',
  names: { 
    key1: 'John Paul', 
    key2: 'Johny Paul',
    key3: 'Johny-paul'
  } 
}

Then I want to apply a function to all names values:

const normalizeString = el => el.normalize('NFD').replace(/[\u0300-\u036f]/g, "");

const normalizedPlayer = {
    ...player,
    namesNormalized: Object.keys(player.names).map(k => ({[k]: normalizeString(player.names[k])}))
}

But I get an array of objects instead of object:

{
  id: 123,
  country: 'GB',
  names: { key1: 'Jóhn Paul', key2: 'Johny Päul', key3: 'Johny-paul' },
  namesNormalized: [
    { key1: 'John Paul' },
    { key2: 'Johny Paul' },
    { key3: 'Johny paul' }
  ]
}

I want namesNormalized like this:

 {
    id: 123,
    country: 'GB',
    names: { key1: 'Jóhn Paul', key2: 'Johny Päul', key3: 'Johny-paul' },
    namesNormalized: { 
     key1: 'John Paul', 
     key2: 'Johny Paul', 
     key3: 'Johny paul' 
   }
 } 

Upvotes: 1

Views: 1421

Answers (5)

Gabe Romualdo
Gabe Romualdo

Reputation: 245

You could loop through each key of the object and then assign that key to the normalized version, like this:

const generateNormalizedObj = (obj) => {
    const normalizedObj = {};
    Object.keys(obj).forEach(key => {
        normalizedObj[key] = obj[key];
    })

    return normalizedObj;
}

Then you could simply set the namesNormalized property in the last variable to be output of that function.

Here's the final code:

const player = {
  id: 123,
  country: 'GB',
  names: { 
    key1: 'John Paul', 
    key2: 'Johny Paul',
    key3: 'Johny-paul'
  } 
}

const normalizeString = el => el.normalize('NFD').replace(/[\u0300-\u036f]/g, "");

const normalizedPlayer = {
    ...player,
    namesNormalized: Object.keys(player.names).map(k => ({[k]: normalizeString(player.names[k])}))
}

const generateNormalizedObj = (obj) => {
    const normalizedObj = {};
    Object.keys(obj).forEach(key => {
        normalizedObj[key] = obj[key];
    })

    return normalizedObj;
}

const normalizedPlayer = {
    ...player,
    namesNormalized: generateNormalizedObj(player.names)
}

Upvotes: 0

Zachary Haber
Zachary Haber

Reputation: 11047

Another possibility is using Object.entries combined with Object.fromEntries.

This lets you avoid having to deal with reducing the properties as fromEntries turns the entries format back to an object.

From Entries works on pretty much all modern major browsers (Can I Use), but there is a shim for it if needed on older browsers.

const player = {
  id: 123,
  country: 'GB',
  names: {
    key1: 'Jóhn Paul',
    key2: 'Johny Päul',
    key3: 'Johny-paul'
  },
}
const normalizeString = el => el.normalize('NFD').replace(/[\u0300-\u036f]/g, "");
const normalizeObject = (obj) => Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, normalizeString(v)]))
const normalizedPlayer = {
  ...player,
  namesNormalized: normalizeObject(player.names)
}


console.log(normalizedPlayer)

Upvotes: 3

kurtko
kurtko

Reputation: 2126

Thanks to @Heretic Monkey to use reduce:

const player = {
  id: 123,
  country: 'GB',
  names: { 
    key1: 'John Paul', 
    key2: 'Johny Paul',
    key3: 'Johny-paul'
  } 
}

const normalizeString = el => el.normalize('NFD').replace(/[\u0300-\u036f]/g, "");

const normalizedPlayer = {      
    ...player,
    namesNormalized: Object.keys(player.names).reduce( (a, k) => ({...a, [k]: normalizeString(player.names[k])}) , {})
}

Upvotes: 1

Ethan Lipkind
Ethan Lipkind

Reputation: 1156

const player = {
  id: 123,
  country: 'GB',
  names: { 
    key1: 'John Paul', 
    key2: 'Johny Paul',
    key3: 'Johny-paul'
  } 
}
const normalizeString = el => el.normalize('NFD').replace(/[\u0300-\u036f]/g, "");

const normalizedPlayer = {
    ...player,
    namesNormalized: Object.keys(player.names).reduce((namesNormalized, k) => {
      return { 
        ...namesNormalized, // spread over previous key/value pairs
        [k]: normalizeString(player.names[k]) // store current key/value pair
      }
    }, {}) // initial value for reducer is an empty object
}

Upvotes: 0

Nenad Vracar
Nenad Vracar

Reputation: 122155

You can use reduce method on Object.entries to return an object and assign it to namesNormalized property.

const player = {
  id: 123,
  country: 'GB',
  names: {
    key1: 'John Paul',
    key2: 'Johny Paul',
    key3: 'Johny-paul'
  }
}

const normalizeString = el => el.normalize('NFD').replace(/[\u0300-\u036f]/g, "");
const normalizedPlayer = { ...player }
normalizedPlayer.namesNormalized = Object.entries(player.names)
  .reduce((r, [k, v]) => Object.assign(r, {
    [k]: normalizeString(v)
  }), {})

console.log(normalizedPlayer)

Upvotes: 1

Related Questions