I have a list that contains other lists and I need to check if a given list item within the same list of lists is in the next item list that belongs to the next list of lists, like in this example:
lstOflsts = [[1,3],[2,6],[8,10],[15,18]]
desired output: check if [1, 3][1]
is in [2, 6]
; if True then [1, 3]
and [2, 6]
will be replaced by [1, 6]
.
lsts = []
for idx, lst in enumerate(lstOflst):
if lst[1] in lstOflsts[idx 1]:
lsts.append([lst[0], lstOflsts[idx 1][1]])
else:
lsts.append(lst)
Can you help me find out how to do this, please? (I got an error in line 2 in the code above)
CodePudding user response:
Assuming the lists are ordered, and assuming they only ever contain 2 elements, which are also ordered, and assuming the intervals never overlap - they are either disjunct or adjoining, then this is a simple solution:
lists = [[1, 3], [2, 8], [8, 10], [15, 18]]
result = [lists[0]]
for lst in lists[1:]:
if result[-1][1] == lst[0]:
result[-1][1] = lst[1]
else:
result.append(lst)
print(result)
Result:
[[1, 3], [2, 10], [15, 18]]
Note: I gave it something to replace.
The logic:
- initialise the result with the first element of the original list
- for each next element in the original, check if the last element of the result has the same end as the start of that next element
- if it does, just update the last element with the end of the next element
- otherwise, add the element to the end
- move on to the next element until done
CodePudding user response:
Avoiding an index error
In the code you provided, an index out of range
error may prompt when reaching lstOflsts[idx 1]
.
To avoid this, I recommend using the following code:
lsts = []
for idx in range(len(lstOflsts) - 1):
if lstOflsts[idx][1] in lstOflsts[idx 1]:
lsts.append([lstOflsts[idx][0], lstOflsts[idx 1][1]])
else:
lsts.append(lstOflsts[idx])
The range argument being len(lstOflsts) - 1
, the last element of lstOflsts
won't be processed in the for loop. All other modifications were made according to this one.
Replacing
1. If you don't want to process already processed elements.
Now, at each iteration of the for loop, your processing an element of index idx
. If the condition is met, you say, the elements of respective indexes idx
and idx 1
have to be replaced. Once replaced (added to the new list lsts
), in the next for iteration, you do NOT want to process these elements you just processed. In this case, you would have to "skip" an iteration. This means increasing deliberately the for loop idx
variable:
lsts = []
for idx in range(len(lstOflsts) - 1):
if lstOflsts[idx][1] in lstOflsts[idx 1]:
for two in range(2): #repeat code twice
lsts.append([lstOflsts[idx][0], lstOflsts[idx 1][1]])
idx = 1 #<--- !
else:
lsts.append(lstOflsts[idx])
2. If you want to process already processed elements.
If you DO want to process elements that were already replaced, it's more likely you'll have to work with one single list of lists. If you want to preserve your original list lstOflsts
, make a copy of it:
from copy import deepcopy
lsts = deepcopy(lstOflsts) #do this only if you want to preserve the original list lstOflsts
for idx in range(len(lsts) - 1):
if lsts[idx][1] in lsts[idx 1]:
lsts[idx] = list[idx 1] = [lsts[idx][0], lsts[idx 1][1]
else:
pass
Here, you are litterally replacing the values in the list. This allows you to keep track of changes in a simple way.
Side remarks
Concerning the deepcopy import, this function is the only one that really works for me when copying lists. But there might be other ones more convenient for your case.
Hope I could help.