1

This is a commonly asked question but I've not found an answer on searches that meets the exact kind of thing I'm trying.

I have a list of items with similar names and I want to add them with a number suffix so that each time, if a duplicate exists, the new item will be incremented to be unique. All the answered searches I found don't split names in character and number. And I need to do that because I'm not just working the original list, I want to append a new item with a unique name. So, I extract a sublist matching the item type, sort it alpha-numerically, split the last item into suffix and prefix, increment the numerical suffix by 1, reform a new item name and append it to the end of the original list. All fine there. Maybe this isn't the most efficient approach but open to suggestions.

Say I have existing list:

mylist = ["point1", "feature1", "point2", "area1", "point3", "feature2", "area2"]

And say if I add a new item point or feature item, it will be automatically renamed point4 or feature3.

So I get the new string name result I want but my final list never appends the newly created item. Where am I going wrong?

So far I have this:

from collections import Counter

mylist = ["point1", "feature1", "point2", "area1", "point3", "feature2", "area2"]

def mysplit(s):
     head = s.rstrip('0123456789')
     tail = s[len(head):]
     return head, tail

# extract items starting with specified string into separate sub list
sublist = [x for x in mylist if x.startswith('point')]
# sort sub list alpha-numerically
sublistSort = sorted(sublist, key=lambda item: (int(item.partition(' ')[0])
                               if item[0].isdigit() else float('inf'), item))
print(sublistSort[-1])


counts = Counter(sublistSort)

for s,num in counts.items():
    if num > 1: # ignore unique names 
        # get last element of sorted sub list
        number = sublistSort[-1]
        # split name and number elements
        number_split = mysplit(number)
        # increment number
        number_inc = number_split[1] + 1 
        # form new element name
        new_number = number_split[0] + number_inc
        # append new element name to original list
        mylist.append(new_number)


print('#########')
print(mylist)

EDIT: so this works, I just need to wrap into a function now. Still interested if anyone thinks of better method using fancy sorting methods etc.,.

mylist = ["point1", "feature1", "point2", "area1", "point3", "feature2", "area2"]

def mysplit(s):
     head = s.rstrip('0123456789')
     tail = s[len(head):]
     return head, tail

# extract items starting with specified string into separate sub list
sublist = [x for x in mylist if x.startswith('point')]
# sort sub list alpha-numerically
sublistSort = sorted(sublist, key=lambda item: (int(item.partition(' ')[0])
                               if item[0].isdigit() else float('inf'), item))
print(sublistSort[-1])

number = sublistSort[-1]
number_split = mysplit(number)
number_inc = str(int(number_split[1]) + 1)
new_number = number_split[0] + number_inc
mylist.append(new_number)

print('#########')
print(mylist)
cvw76
  • 99
  • 1
  • 9
  • Actually, just figured it. I didn't need to ignore unique names (as there are all unique in this instance) but more importantly, my list wasn't appending because I didn't cast the number_inc correctly as an int then str. Works now. Still be interested if anyone has better approaches to the idea in general. – cvw76 Feb 03 '18 at 14:22
  • Well done for working out the solution to your issue. – Suraj Kothari Feb 03 '18 at 14:32
  • I would suggest to use another data-structure. Can't you just store them as `"point`" and `"feature"` together with a number telling how many you have of them? – Elmex80s Feb 03 '18 at 14:42
  • Hmm. Not sure. These are graphical elements in a process graph, I generate a unique name to the general type so I can give specific objects a unique name without using id(). The graph objects are built on the fly at runtime, I use the name attributes on each object for saving to xml files between sessions and so be able to ensure that I can rebuild the graph sessions each time. – cvw76 Feb 03 '18 at 14:51

3 Answers3

1

General solution is like this :

def get_index(mylist, new_element):
    index = 1
    for p in mylist:
        if p[:len(new_element)] == new_element:
            index = p[len(new_element):]
    return int(index) + 1

mylist = ["point1", "feature1", "point2", "area1", "point3", "feature2", "area2"]
new_element = 'point'
mylist.append(new_element + str(get_index(mylist, new_element)))

print mylist

Or just :

def add_new_element(mylist, new_element):
    index = 1
    for p in mylist:
        if p[:len(new_element)] == new_element:
            index = p[len(new_element):]
    mylist.append(new_element + str(int(index) + 1))

Outputs

['point1', 'feature1', 'point2', 'area1', 'point3', 'feature2', 'area2', 'point4']

The idea is :

  • search for the element in the list
  • if the element exit then take the number, i named it index
  • return index + 1
  • then you can just append it to your list
Youcef LAIDANI
  • 55,661
  • 15
  • 90
  • 140
1

You can use lambda expressions to filter your list to only contain elements of the same type as your new element. Then you can use the length of this list to find out the new index and append the new item accordingly:

mylist = ["point1", "feature1", "point2", "area1", "point3", "feature2", "area2"]

def append_item(new_item):
    entries_list = filter(lambda x: new_item in x, mylist)
    new_entry = new_item + (len(entries_list) + 1).__str__() 
    mylist.append(new_entry)

append_item("area")
Nils Schlüter
  • 1,418
  • 1
  • 19
  • 30
0

This is little different approach , If you want you can use:

mylist = ["point1", "feature1", "point2", "area1", "point3", "feature2", "area2"]

from collections import defaultdict
import itertools
d=defaultdict(list)
for i in mylist:
    d[i[:-1]].append(i)

def no_dublicate(append_items):
    for i in append_items:
        for k, m in d.items():
            if i == k:
                d[k].append(i + str(len(m) + 1))

    return sum(d.values(),[])


print(no_dublicate(['area','area','area','feature','feature','point','feature']))

output:

['point1', 'point2', 'point3', 'point4', 'feature1', 'feature2', 'feature3', 'feature4', 'feature5', 'area1', 'area2', 'area3', 'area4', 'area5']
Aaditya Ura
  • 12,007
  • 7
  • 50
  • 88