jay747
jay747

Reputation: 47

How do i rename duplicate elements in python list of lists based on vertical position?

I have a list of lists like this:

listofLists = [
                ['a', 'b', 'e'],
                ['a', 'd'],
                ['a', 'c'],
                ['a', 'b', 'c', 'e'],
                ['a', 'e', 'c', 'f']
                ]

How can i read this element list vertically and rename duplicates appending numbers to the element in incremental order? The output list has to preserve the same order.

For example, first position of 'e' is at index 1 in list ['a', 'e', 'c', 'f'], it should remain as it is. Next position of 'e' is at index 2 in list ['a', 'b', 'e'] which should be renamed as 'e1'. The last position of 'e' is in list ['a', 'b', 'c', 'e'] which should be renamed as 'e3'

The required output should be:

requiredOutput = [['a', 'b', 'e1'],
                  ['a', 'd'],
                  ['a', 'c'],
                  ['a', 'b', 'c1', 'e2'],
                  ['a', 'e', 'c1', 'f']]

The code i have tried is as below, by checking against a transposed list. But it does not give me the required output since my code changes the current element of the list. I dont know if this is the right approach to the problem statement.

transformedListOfTuples = list(zip_longest(*listofLists))
transformedListOfList= [list(x) for x in transformedListOfTuples]
for i in range(0, len(listofLists)):
    for j in range(0, len(listofLists[i])):
        pos = -1
        for z in range(0, len(transformedListOfList)):
            if listofLists[i][j] in transformedListOfList[z]:
                pos = pos + 1
                if pos == 0:
                    continue
                elif pos > 0:
                    listofLists[i][j] = listofLists[i][j] + str(pos)
            elif listofLists[i][j] not in transformedListOfList[z]:
                continue

Upvotes: 3

Views: 225

Answers (2)

kederrac
kederrac

Reputation: 17322

you can use:

previous = {}
for i in range(max(len(e) for e in listofLists)):
    col = [l[i] for l in listofLists if len(l) > i]
    previous.update({e: previous.get(e, 0) + 1 for e in set(col)})

    for l in listofLists:
        if len(l) > i:
            if previous[l[i]] > 1:
                l[i] = l[i] + str(previous[l[i]] - 1)
listofLists

output:

[['a', 'b', 'e1'],
 ['a', 'd'],
 ['a', 'c'],
 ['a', 'b', 'c1', 'e2'],
 ['a', 'e', 'c1', 'f']]

how it works: previous dict will store the current number of occurrences of an element per columns, the first for loop iterate over all columns, at each iteration step the previous dict it is updated base on the elements from the current column, the inner for loop will update each element from the current column if the number of occurrences per columns is more than 1

or you can use:

from itertools import accumulate, zip_longest
from collections import Counter

cols = list(zip_longest(*listofLists))
t = [[f'{e}{a[e] - 1}' if e and a[e] > 1 else e for e in i] for i, a in
     zip(cols, accumulate((Counter(set(l)) for l in cols)))]
listofLists = [[e[i] for e in t if e[i]] for i in range(len(t[0]))]

you operate per column and get the transpose of your desired output (this is t)

Upvotes: 1

Robo Mop
Robo Mop

Reputation: 3553

How about this:

arr = [
    ['a', 'b', 'e'],
    ['a', 'd'],
    ['a', 'c'],
    ['a', 'b', 'c', 'e'],
    ['a', 'e', 'c', 'f']
]

listOfRepeated = []
max_len = 0

for i in range(0, len(arr)):
    if max_len < len(arr[i]):
        max_len = len(arr[i])

for j in range(0, max_len):
    list_to_add = []
    for i in range(0, len(arr)):
        if j < len(arr[i]):
            val = arr[i][j]
            # For each iteration of `i`, you'll go down the group

            if not val in list_to_add:
                list_to_add.append(val)
            
            count = listOfRepeated.count(val)
            if count > 0:
                arr[i][j] = ""+str(val)+""+str(count)

    for element in list_to_add:
        listOfRepeated.append(element)

for list in arr:
    print(list)

Output:

['a', 'b', 'e1']
['a', 'd']
['a', 'c']
['a', 'b', 'c1', 'e2']
['a', 'e', 'c1', 'f']

Explanation:

j is the counter to go horizontally, i is the counter to go down the group. Every element is present at arr[i][j]

list_to_add is a list that contains every unique character for a particular group

listOfRepeated is a list of every element that has been seen so far. If you're present in listOfRepeated once, that means your current group is the first one with the character. If it is more than once, that means you need to add a number after the character.

Upvotes: 2

Related Questions