I am trying to replace all None
values in all sublists within a list to incremental numbers starting from 0 but excluding the numbers from the skip list. And there is one more requirement. If first element of a sublist matches to any other sublists' first element, then they all need to have the same value that replaces None
in them if present. This is what I could try so far.
skip = [1,2]
a = [[1, None, 2], [3, 4, 5], [1, None, 7], [8, 9, 10],[11, None, 12]]
b = 0
d = {}
for i in range(len(a)):
if a[i][1]==None:
if b in skip:
print("found b in skip")
b = b 1
if a[i][1] in d.keys():
a[i][1] = d[a[i][1]]
else:
a[i][1] = b
d[a[i][0]] = b
b = b 1
print(d)
print(a)
Output:
found b in skip
{1: 2, 11: 3}
[[1, 0, 2], [3, 4, 5], [1, 2, 7], [8, 9, 10], [11, 3, 12]]
Expected output:
[[1, 0, 2], [3, 4, 5], [1, 0, 7], [8, 9, 10], [11, 3, 12]]
CodePudding user response:
You're looking up the wrong element in the cache in a couple places, and not skipping properly when the skip
list contains consecutive elements. Here's the minimal fix with inline comments indicating changed lines:
skip = [1,2]
a = [[1, None, 2], [3, 4, 5], [1, None, 7], [8, 9, 10],[11, None, 12]]
b = 0
d = {}
for i in range(len(a)):
if a[i][1]==None:
while b in skip: # Loop until skipped all elements in skip
print("found b in skip")
b = b 1
if a[i][0] in d.keys(): # Check for first, not second element
a[i][1] = d[a[i][0]] # Use first element, not second, for lookup
else:
a[i][1] = b
d[a[i][0]] = b # Indent so we only set cached value on cache miss
b = b 1 # Indent so we only increment b on new first element
print(d)
print(a)
And here's a more heavily modified version that is somewhat more Pythonic, using names, not indexing (when possible):
skip = {1,2} # Use set instead of list; if skip is large, list membership check will be expensive, set will stay cheap
a = [[1, None, 2], [3, 4, 5], [1, None, 7], [8, 9, 10],[11, None, 12]]
b = 0
d = {}
for sublist in a: # Loop over values instead of indexing a over and over, C-style (slow and less readable)
first, middle, _ = sublist # Unpack to useful names (reducing risk of misindexing, and making more readable code)
# Not unpacking in for loop itself because we need to reassign elements of sublist
if middle is None: # Always use is/is not to compare to None
while b in skip:
b = 1 # Use = to avoid repeating variable name
if first in d: # No need for .keys(); "in d" has same effect as "in d.keys()" and avoids creating unnecessary keys view
sublist[1] = d[first] # Indexing needed for assignment to modify original list
else:
sublist[1] = d[first] = b # Can populate cache and reassign middle value all at once
b = 1
print(d)
print(a)
Either version gets the expected output from the question.
CodePudding user response:
Here is my approach to solve this, It's lengthy but easy to follow. This considers if None
is the first item or last item as well, not just the middle item. So it's a little bit more general. I've put comments for explanation:
skip = {1, 2}
lst = [[1, None, 2], [3, 4, 5], [1, None, 7], [8, 9, 10], [11, None, 12]]
# Filling a dictionary which groups sublists based on first item.
d = {}
for sublist in lst:
first, mid, last = sublist
if first is None: # No need to add to the dictionary because later, we won't traverse if the first item is None.
continue
if first in d:
d[first].append(sublist)
else:
d[first] = [sublist]
# A generator which yields correct next value
def increment_counter():
counter = 0
while True:
if counter not in skip:
yield counter
counter = 1
counter = increment_counter()
for sublist in lst:
if all(item is not None for item in sublist):
continue
first, middle, last = sublist
if first is None: # No check is needed if None is the first item.
sublist[0] = next(counter)
else: # Either middle or last item is None. We need to travers our dictionary.
n = next(counter)
for l in d[first]:
for i, item in enumerate(l):
if item is None:
l[i] = n
print(lst)
output:
[[1, 0, 2], [3, 4, 5], [1, 0, 7], [8, 9, 10], [11, 3, 12]]
This also works for lists like:
[[1, None, 2], [3, 4, 5], [1, None, 7], [8, 9, 10], [11, 12, None], [None, 12, 5]]