better way to replace multple substring with dynamic length array?

I have a lot of strings and I am replacing "xxx" with elements of an array. These arrays can have different lengths. My code is currently working but I am not sure if this is the best way. How would you do it or would you optimize it?

var items = [{
    str: 'This is xxx an he is xxx years old ',
    list: ['Frank', '14']
  },
  {
    str: 'xxx and xxx are xxx ',
    list: ['George', 'John', "studying"]
  }
]


items.forEach(item => {
  item.list.forEach(s => {
    item.str = item.str.replace("xxx", s)
  })
  console.log(item.str);
})

2 answers

  • answered 2018-11-08 00:42 ibrahim mahrir

    If the strings are too long or if the replacements can have the substring "xxx" in them, then you'd be better off using a regex with the global modifier and use the callback of replace to select an item from the array using an index:

    items.forEach(item => {
      let index = 0;
      item.str = item.str.replace(/xxx/g, m => item.list[index++]);
    });
    

    Otherwise, your solution is just fine.

    Notes:

    1- You may want to check if index goes beyond item.list.length in case there are more xxx than there are items in item.list. A safe solution would be:

    item.str = item.str.replace(/xxx/g, m => item.list[index++] || m);
    

    Which replaces by m if item.list[index++] is undefined.

    2- If you don't care about mutating item.list, then the whole solution could be a lot shorter by using shift instead of the index:

    items.forEach(item => item.str.replace(/xxx/g, m => item.list.shift() || m));
    

    Example:

    var items = [{
        str: 'This is xxx an he is xxx years old ',
        list: ['Frank', '14']
      },
      {
        str: 'xxx and xxx are xxx ',
        list: ['George', 'John', "studying"]
      }
    ]
    
    
    items.forEach(item => {
      let index = 0;
      item.str = item.str.replace(/xxx/g, m => item.list[index++]);
    })
    
    console.log(items);

  • answered 2018-11-08 05:00 numbtongue

    You can get rid off one of the for each with this approach.. Here you are searching for all "xxx" with regexp in "str" and use array shift() method to return and remove first element from the "list" array..

    var items = [{
        str: 'This is xxx an he is xxx years old ',
        list: ['Frank', '14']
      },
      {
        str: 'xxx and xxx are xxx ',
        list: ['George', 'John', "studying"]
      }
    ]
    
    
    items.forEach(item => {
    
        item.str = item.str.replace(/xxx/g,function (x) {
            return item.list.shift();
        });
    
        // item.list.forEach(s => {
        //   item.str = item.str.replace("xxx", s)
        // })
    
      console.log(item.str);
    })