skip to Main Content

I’ve got a following array of objects

let views = [
  {
    name: "A View",
    active: true,
  },
  {
    name: "B View",
    active: false,
  },
  {
    name: "C View",
    active: false,
  }
];

When another elements are added, one by one with the existing name, for example another "A View", and another "A View" like for example

{
  name: "A View",
  active: true,
}

I want to add the suffix number to the name in the counting order, so I’ve got

[
  {
    name: "A View",
    active: true,
  },
  {
    name: "B View",
    active: false,
  },
  {
    name: "C View",
    active: false,
  },
  {
    name: "A View 2",
    active: true,
  }
]

after the first new "A View" added

And

[
  {
    name: "A View",
    active: true,
  },
  {
    name: "B View",
    active: false,
  },
  {
    name: "C View",
    active: false,
  },
  {
    name: "A View 2",
    active: true,
  },
  {
    name: "A View 3",
    active: true,
  }
];

after the second "A View" element added, and so on…
Is I then remove "A View 2" I want the "2" suffix to be available to add for the new "A view" if I add it. So the next "A View" item will be "A View 2", not "A View 4"

This is my current solution

const addItem = (item) => {
  views = [...views, item];
  let names = {};

  views.forEach((obj) => {
    if (names[obj.name]) {
      obj.name += " " + ++names[obj.name];
    } else {
      names[obj.name] = 1;
    }
  });

  console.log("views", views);
};

The problem is that the suffix is not adding correctly.
If I call the function 3 times passing the same object, like for example

addItem({
  name: "A View",
  active: true,
});

I will have this

enter image description here

Here is the working example – https://codesandbox.io/p/sandbox/8dhpl3

2

Answers


  1. This seems to cover your requirement, although perhaps it can be optimised a little more

    let views = [
      {
        name: "A View",
        active: true,
      },
      {
        name: "B View",
        active: false,
      },
      {
        name: "C View",
        active: false,
      },
    ];
    
    const addItem = (item) => {
      let names = {};
    
      views.forEach((obj) => {
          names[obj.name] = 1;
      });
      
      let _suffix = "";
      let _suffix_ctr = 1;
      while (names[item.name + _suffix]) {
          _suffix_ctr++;
          _suffix = " " + _suffix_ctr;
      }
      
      let new_name = item.name + _suffix;
      views = [...views, {...item, name: new_name}]
    
      console.log("views", views);
    };
    
    addItem({
      name: "A View",
      active: true,
    });
    
    addItem({
      name: "A View",
      active: true,
    });
    
    addItem({
      name: "A View",
      active: true,
    });
    
    Login or Signup to reply.
  2. addItem is adding suffixes to all the items that are already in the array. It should only append it to the new item you’re adding.

    So it should look for existing items that have the same name, or the same name with some suffix. It should add 1 to the highest of these.

    In my code below I use a dynamically-generated regular expression to match the name with an optional suffix.

    const addItem = (views, item) => {
      let name_regexp = new RegExp(`^${item.name}(?: (\d+))?$`);
      let max_index = 0;
    
      views.forEach((obj) => {
        let match = obj.name.match(name_regexp);
        if (match) {
          let index;
          if (match[1]) {
            index = parseInt(match[1]);
          } else {
            index = 1;
          }
          if (index > max_index) {
            max_index = index;
          }
        }
      });
      if (max_index) {
        item.name += " " + (max_index + 1);
      }
      views.push(item);
    };
    
    addItem(views, {
      name: "A View",
      active: true,
    });
    addItem(views, {
      name: "A View",
      active: true,
    });
    addItem(views, {
      name: "A View",
      active: true,
    });
    
    console.log("views", views);
    <script>
    let views = [
      {
        name: "A View",
        active: true,
      },
      {
        name: "B View",
        active: false,
      },
      {
        name: "C View",
        active: false,
      }
    ];
    </script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search