Reputation: 1178
I've a list of lists like this:
[[10000, 10001, 10002, 115050, 11506,11786,11787, 11788], [12553,12554,10001,10002], [9500, 9501, 9502, 9503, 9759, 9760, 9761, 11778,11779, 11780, 11781,11782, 12112, 12113]]
What I want to do is, find the duplicate values that are in these lists, and change them by 1 or 2 as required, so that there would be no duplicate or overlap at all. I can't change them to random values, because they are pixel values and changing them hugely will distort my result.
I tried something like this:
even = [[10000, 10001, 10002, 115050, 11506,11786,11787, 11788], [12553,12554,10001,10002], [9500, 9501, 9502, 9503, 9759, 9760, 9761, 11778,11779, 11780, 11781,11782, 11788, 11789, 12112, 12113]]
if(len(even)>1):
inter = []
for i in range(len(even)-1):
#intersections = [set(even[i]).intersection(even[j]) for j in range(i+1, len(even)) ]
for j in range(i+1, len(even)-1):
intersect = list(set(even[i]).intersection(even[j]))
if len(intersect)>0:
for inte in intersect:
even[j][even[j].index(inte)] =even[j][even[j].index(inte)]+1
print("we changed the value here", index)
print(even)
This is hardly and decent solution, because it fails in this very example. I tried to do it with numpy as well.
length = len(sorted(even,key=len, reverse=True)[0])
y=np.array([xi+[None]*(length-len(xi)) for xi in even])
print( y, even)
y[:,1:] *=(np.diff(y,axis=1)!=0)
However this code would change the duplicate values to 0, which I don't desire. Any help would be really appreciated.
Two things to Note: there shouldn't be any duplicate value in any of the lists inside the list, and the changed value shouldn't have the huge difference, 1,2 + or - depending upon, how we can mitigate the duplication. Thanks in advance.
Upvotes: 4
Views: 684
Reputation: 294218
You can create a closure and return a function to apply to every element that remembers all elements that have been seen.
def f():
seen = set() # Thing that sees all
def g(a): # New function that will refer to `seen`
while a in seen:
a += 1 # Keep adding one until we find one not in `seen`
seen.add(a)
return a
return g # Return the function that remembers `seen`
t = f()
even = [[1, 2], [2, 3], [4, 7]]
# not apply `t` ourselves
# neither `t` nor `f` need to know about the structure of `even`
[[t(x) for x in row] for row in even]
[[1, 2], [3, 4], [5, 7]]
We can take this a step further and create a generator that traverses arbitrarily nested lists
from collections.abc import Iterable
def h(i, t=None):
if t is None:
t = f()
for x in i:
if isinstance(x, Iterable) and not isinstance(x, str):
yield [*h(x, t)]
else:
yield t(x)
Does it work on even
?
[*h(even)]
[[1, 2], [3, 4], [5, 7]]
What about something more complicated?
[*h([1, 2, [1, 2], 3, 4, 9, [1, [20, 21, 21]]])]
[1, 2, [3, 4], 5, 6, 9, [7, [20, 21, 22]]]
Upvotes: 3
Reputation: 249123
Here's an in-place solution:
def dedupe(lol):
seen = set()
for lst in lol:
for ii, val in enumerate(lst):
while val in seen:
val += 1
lst[ii] = val
seen.add(val)
And here's a generator which does not modify the input:
def dedupe(lol):
seen = set()
for lst in lol:
new = []
for val in lst:
while val in seen:
val += 1
new.append(val)
seen.add(val)
yield new
You can use it like print(list(dedupe(l))
.
Upvotes: 2