skip to Main Content

I have an object that can have multiple named "url" keys, that they are on different levels of depth, they can change.

I need that every key named url found, replace its value for a new one.

-1 Using map:

const array = [
    {
        name: "Patrick",
        age: 21,
        socials: [
            {
                name: 'Twitter',
                url: "www.twitter.com/patrick",
            },
            {
                name: 'Facebook',
                url: 'www.facebook.com/patrick'
            }
        ],
        contact: {
            phoneNumber: 5842435534,
            email: '[email protected]',
            websites: [
                {
                    name: 'Github',
                    url: 'www.github.com/patrick'
                },
                {
                    name: 'StackOverflow',
                    url: 'www.stackoverflow.com/users/329423/patrick'
                }
            ]
        }
    },
    {
        name: "John",
        age: 22,
        socials: [
            {
                name: 'Twitter',
                url: "www.twitter.com/john",
            },
            {
                name: 'Facebook',
                url: 'www.facebook.com/john'
            }
        ],
        contact: {
            phoneNumber: 5842433334,
            email: '[email protected]',
            websites: [
                {
                    name: 'Github',
                    url: 'www.github.com/john'
                },
                {
                    name: 'StackOverflow',
                    url: 'www.stackoverflow.com/users/329433/john'
                }
            ]
        }
    }
]

And this is the map:

const arrayMap = array.map(person => {
    return {
        name: person.name,
        age: person.age,
        socials: person.socials.map(social => {
            return {
                name: social.name,
                url: `https://${social.url}`
            }
        }),
        contact: {
            phoneNumber: person.contact.phoneNumber,
            email: person.contact.email,
            websites: person.contact.websites.map(website => {
                return {
                    name: website.name,
                    url: `https://${website.url}`
                }
            })
        }
    }
})

2- Using regexp:

const array = [
    {
        name: "Patrick",
        age: 21,
        socials: [
            {
                name: 'Twitter',
                url: "www.twitter.com/patrick",
            },
            {
                name: 'Facebook',
                url: 'www.facebook.com/patrick'
            }
        ],
        contact: {
            phoneNumber: 5842435534,
            email: '[email protected]',
            websites: [
                {
                    name: 'Github',
                    url: 'www.github.com/patrick'
                },
                {
                    name: 'StackOverflow',
                    url: 'www.stackoverflow.com/users/329423/patrick'
                }
            ]
        }
    },
    {
        name: "John",
        age: 22,
        socials: [
            {
                name: 'Twitter',
                url: "www.twitter.com/john",
            },
            {
                name: 'Facebook',
                url: 'www.facebook.com/john'
            }
        ],
        contact: {
            phoneNumber: 5842433334,
            email: '[email protected]',
            websites: [
                {
                    name: 'Github',
                    url: 'www.github.com/john'
                },
                {
                    name: 'StackOverflow',
                    url: 'www.stackoverflow.com/users/329433/john'
                }
            ]
        }
    }
]
const newArray = JSON.stringify(array);

const regex = /"url":"([^"]+)"/g;
const result = newArray.replace(regex, '"url":"https://$1"');

console.log(JSON.parse(result));

With these methods, my code works, but I don’t know if it’s optimized or if exists a better way to do it considering it can have between 20-100 items.

Any ideas?

2

Answers


  1. If you’re list only has 20-100 items you don’t really have to worry about performance (you’ll start to feel differences at 100 thousand to 1 million entries, depending on the environment and machine).

    If you’re worried about performance, the regex version sure looks pretty but is very unperformant (you have to traverse the contents three times, once to stringify it, once to replace, and once to parse again).

    The following is just your mapping code but slightly improved and less verbose:

    const addProtocol = arr => arr.map(entry => ({
      ...entry,
      socials: entry.socials.map(({ name, url }) => ({ name, url: "https://" + url })),
      contact: {
        ...entry.contact,
        websites: entry.contact.websites.map(({ name, url }) => ({
          name,
          url: "https://" + url
        }))
      }
    }))
    
    const array = [{
        name: "Patrick",
        age: 21,
        socials: [{
            name: 'Twitter',
            url: "www.twitter.com/patrick",
          },
          {
            name: 'Facebook',
            url: 'www.facebook.com/patrick'
          }
        ],
        contact: {
          phoneNumber: 5842435534,
          email: '[email protected]',
          websites: [{
              name: 'Github',
              url: 'www.github.com/patrick'
            },
            {
              name: 'StackOverflow',
              url: 'www.stackoverflow.com/users/329423/patrick'
            }
          ]
        }
      },
      {
        name: "John",
        age: 22,
        socials: [{
            name: 'Twitter',
            url: "www.twitter.com/john",
          },
          {
            name: 'Facebook',
            url: 'www.facebook.com/john'
          }
        ],
        contact: {
          phoneNumber: 5842433334,
          email: '[email protected]',
          websites: [{
              name: 'Github',
              url: 'www.github.com/john'
            },
            {
              name: 'StackOverflow',
              url: 'www.stackoverflow.com/users/329433/john'
            }
          ]
        }
      }
    ]
    console.log(addProtocol(array))
    Login or Signup to reply.
  2. It is hard to know which method is going to be the fastest without doing benchmarks. 20-100 items is very small and you should not optimize too early on this if the size is going to stay in this range.

    If you really have no structure in your object that can speep things up, you will need to traverse the object. For this there are modules like https://www.npmjs.com/package/gdeep-replace

    The regex method that stringifies the object can be fast because stringify is highly optimized, but regex-replacing a json is prone to errors because the regex can seem simple but there may be corner cases that quickly become bugs. People try to avoid using regexp as a json parser for good reasons.

    The map solution is heavy because you recreate the whole object.

    But the map solution seem to show that you are ready to accept some structure in the object (an array of user objects with urls only in specific places.

    If you don’t care about immutability and are ready to accept the mutation of the object, the fastest will probably be an in-place replacement of the urls where there are with something like

    array.map(person => {
      person.socials.map(social => { social.url = "https://" + social.url })
      person.contact.websites.map(website => { website.url = "https://" + website.url })
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search