Reputation: 47
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
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
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']
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