Find the index of a tuple when iterating across the first element of the tuple - python-3.x

How can you identify the index of a tuple when looping through a list of tuples[0]?
List = [('SPAM', 1.0),('EGGS', 4.2),('SPAM', 4.4),('BACON', 9.0),('COFFEE', 2.3)]
for i,j in List:
if i == 'SPAM':
list.remove(???)
print(list)
I've tried to employ the Enumerate() function, but that didn't seem to give me the correct output either.
List.pop()
Doesn't pop the correct index all the time.
Can anyone help, please?

Enumeration does work:
l = [('SPAM', 1.0),('EGGS', 4.2),('SPAM', 4.4),('BACON', 9.0),('COFFEE', 2.3)]
for idx, (i,j) in enumerate(l):
if i == 'SPAM':
print("FOUND SPAN at index %d" % idx)
However, you shouldn't mutate the list while iterating over it, rather take a filtering approach like so:
l_new = [(i, j) for i, j in l if i != 'SPAM']

You can use del to delete the element at the given index:
List = [('SPAM', 1.0),('EGGS', 4.2),('SPAM', 4.4),('BACON', 9.0),('COFFEE', 2.3)]
for (i, (e1, e2)) in enumerate(List):
if e1 == 'SPAM':
del List[i]
print(List) # prints [('EGGS', 4.2), ('BACON', 9.0), ('COFFEE', 2.3)]

Related

How to update multiple key and values in dictionary?

Input:
lst = {"scot":{"23", "poland"}, "martin":{"32", "england"},
"":{"23", "ireland"},None:{"23", "indian"}, "1":{"", ""}}
Output:
lst2 = {"scot":{"230", "poland"}, "martin":{"320", "england"},
"":{"230", "ireland"},None:{"230", "indian"}, "10":{"", ""}}
Code :
for k,v in lst.items():
if k is not None:
if k.isdigit():
k = k + "0"
print(k)
if v is not None and type(v) == set :
for i in v:
if i.isdigit():
i =i + "0"
print (i)
print(lst)
But The values are not getting updated and I am getting below output:
{'scot': {'23', 'poland'}, 'martin': {'england', '32'}, '': {'23', 'ireland'}, None: {'23', 'indian'}, '1': {''}}
You were on the right track, but you were not updating the actual values in your dictionary. More importantly, you shouldn't be changing the iterables (dicts, sets, lists) while iterating through them - in the sense that you shouldn't be adding or removing new elements that would normally be part of the iteration (like add or remove key-value pairs while iterating through a dictionary).
Because of that, a simple implementation of your program needs to have two parts - first where you search your dictionary lst and record the necessary changes, and second where you implement those recorded changes.
Below code does just that,
lst = {"scot":{"23", "poland"}, "martin":{"32", "england"}, "":{"23", "ireland"},None:{"23", "indian"}, "1":{"", ""}}
keys_to_delete = []
kv_pairs_to_add = {}
ks_pairs_to_swap = []
# Collect what needs to change
for k,v in lst.items():
if k is not None:
if k.isdigit():
# Save the old key for later deletion
keys_to_delete.append(k)
# Create and record the new entry
kv_pairs_to_add[k + "0"] = v
k += "0"
print(k)
# ------ Was this supposed to be v or k?
if v is not None and type(v) == set:
for i in v:
if i.isdigit():
# Record the key, old value,
# and new value as a sublist
ks_pairs_to_swap.append([k, i, i+"0"])
i += "0"
print (i)
# Implement the changes
# Dictionary keys
for key in keys_to_delete:
del lst[key]
lst.update(kv_pairs_to_add)
# Sets
for key, ov, nv in ks_pairs_to_swap:
lst[key].remove(ov)
lst[key].add(nv)
print(lst)
Note the comment with ------ - just checking if vthere is not a bug, it seems your keys can be None, so the check should maybe be for k and not v.
I never put the code into my IDE but looking at your code it does seem to be right but I noticed that you're not ACTUALLY updating your list, your only creating variable.
For example
for k,v in lst.items():
This creates two variables k,v and you use those variables in the for loop with if statements, in order to actually update it you'd have to figure out a way to remove the previous string and append the new updated variable k or v
In the if statement you're not actually appending and removing anything from the dictionary you are only adding something to k or v and printing the variable out.
I don't think I wrote this well, but I hope I gave you a possible clear understanding on why its not actually getting updated.
lst = {"scot": {"23", "poland"}, "martin": {"32", "england"}, "": {"23", "ireland"}, None: {"23", "indian"}, "1": {"", ""}}
result = {}
for k, v in lst.items():
if k is not None or str:
for i in v:
if i.isdigit():
i += "0"
else:
j = i
result[k] = {i, j}
print(result)
Output:
{'scot': {'poland', '230'}, 'martin': {'england', "320"}, '': {'230', 'ireland'}, None: {'230', 'indian'}, '1': {''}}

Screening for duplicates in a tuple - Python

I am trying to create a function, non_duplicates(), that screens for duplicates for a given tuple x, and returns False if there is a duplicate, or returns True if there isn't any.
I am doing this by a for loop nested within another to iterate over the items twice to compare all the items with each other. I added a conditional that checks if the two items are equal, while their indices are not.
The problem is that the code is giving an equal index for different items for some reason, where I made sure that the index is linked with the iteration.
The answer for non_duplicates(((0,0),(0,0))) is the same as non_duplicates(((0,0),(5,5))), both are giving True while it should not for the former.
When I checked ((0,0),(0,0)), the indices are "0,0 0,0 0,0 0,0", while for ((0,0),(5,5)), the indices are "0,0 0,1 1,0 1,1".
That is why the condition are not being met.
def non_duplicates(x):
y = 0
for i, j in x:
x1 = (i,j)
for k, l in x:
x2 = (k,l)
if (x1 == x2 and x.index(x1) != x.index(x2)):
y = y + 1
y = y/len(x)
if y == 0:
answer = True
if y > 0:
answer = False
return answer
If I understand the question correctly, you can try:
def non_duplicates(x):
return len(set(x)) == len(x)
Here is an answer that uses the same logic as #Matt Shin's answer but also works for a tuple of tuples like your example show's you checking.
def non_duplicates(x):
sorted_tuples = []
for item in x:
# sort every tuple in a tuple of tuples and returns a list of sorted tuples
sorted_tuples.append(tuple(sorted(item)))
# checks for duplicates using set
return len(set(sorted_tuples)) == len(sorted_tuples)
print(non_duplicates(((0,0),(0,0))))
print(non_duplicates(((0,0),(5,5))))
Or if your tuple of tuples is really large and you care deeply about computation time. You could check after every element you add.
def non_duplicates(x):
sorted_tuples = set()
for count, item in enumerate(x, 1):
sorted_tuples.add(tuple(sorted(item)))
if len(sorted_tuples) != count:
return False
return True

updating tuple string and how to optimize my code

I have one list like that :
[`('__label__c091cb93-c737-4a67-95d7-49feecc6456c', 0.5), ('__label__96693d45-4dec-4b66-a2e2-621329d64b92', 0.498047)]`
I want to replace tuple element string value like this:
'__label__c091cb93-c737-4a67-95d7-49feecc6456c' to 'c091cb93-c737-4a67-95d7-49feecc6456c'
I try this :
l = [('__label__c091cb93-c737-4a67-95d7-49feecc6456c', 0.5), ('__label__96693d45-4dec-4b66-a2e2-621329d64b92', 0.498047)]
j = []
for x in l:
for y in x:
if type(y) == str:
z = y.replace('__label__',"")
j.append((z, x[1]))
print(j)
Output:
[('c091cb93-c737-4a67-95d7-49feecc6456c', 0.5), ('96693d45-4dec-4b66-a2e2-621329d64b92', 0.498047)]
how to optimize my code in pythonic way and any other way to update tuple value because tuple is immutable
You are right, tuples are immutables in Python, but lists are not. So you should be able to update the list l in-place.
Moreover, it looks like you already know the position of the element you have to modify and the position of the substring you want to remove, so you can avoid one loop and the replace function which will iterate once more over your string.
for i in range(len(l)):
the_tuple = l[i]
if isinstance(the_tuple[0], str) and the_tuple[0].startswith('__label__'):
l[i] = (the_tuple[0][len('__label__'):], the_tuple[1])
# you can also replace "len('__label__')" by "8" to increase performances
# but I think Python already optimizes it
You can use map function:
data = [('__label__c091cb93-c737-4a67-95d7-49feecc6456c', 0.5), ('__label__96693d45-4dec-4b66-a2e2-621329d64b92', 0.498047)]
def f(row): return row[0].replace('__label__', ''), row[1]
print(list(map(f, data)))

How to remove tuple from zip?

so i have a bunch of numbers i've tupled but am having difficulty remove an item from the zipped list.
so far i've tried .remove on the list but that gave me an error.
is there an easy way of doing this?
this is my current code:
Example data:
QueenRowColumn: 3,3
TheComparisonQueen: 7,3
def CheckQueenPathDown(self, QueenRowColumn, TheComparisonQueen):
row = []
column = []
CurrentLocation = QueenRowColumn
#MoveLocation = TheComparisonQueen
a = QueenRowColumn[0]
b = QueenRowColumn[1]
for i in range (-7,0):
row.append(CurrentLocation[1] - i)
column.append(a)
Down = zip(row,column)
#Down.remove(TheComparisonQueen)
return Down
if i, for example were to remove "TheComparisonQueen" from the list of tuples, how would i do it?
If you just looking to drop TheComparisonQueen from iterator of tuples you can return values that are not equal to TheComparisonQueen using a list comprehension or a generator expression.
# List Comprehension
Down = [(i,j) for i,j in zip(row,column) if (i,j) != TheComparisonQueen]
# Generator Expression
Down = ((i,j) for i,j in zip(row,column) if (i,j) != TheComparisonQueen)

k way merge sort divide and conquer

from math import ceil
def merge(all_lst):
sorted_lst = []
while all_lst:
min_value,index = all_lst[0][0],0
for lst in all_lst:
if lst[0]<min_value:
min_value = lst[0]
index = all_lst.index(lst)
sorted_lst.append(min_value)
all_lst[index].pop(0)
if not all_lst[index]:
all_lst.remove(all_lst[index])
return sorted_lst
def merge_sort(lst, k):
def split(lst):
split_lst = []
j = ceil(len(lst)/k) if len(lst)>=k else 1
for i in range(0,len(lst),j):
split_lst.append(lst[i:i+j])
return split_lst
lst=split(lst)
if len(lst[0])==1:
return lst
else:
for i in range(len(lst)):
lst[i]=merge(merge_sort(lst[i],k))
return merge(lst)
Above is my code for k-way merge sort. Basically what it does is split the list into k smaller list by calling the split function until each sublist in the list is a single element. Then the list containing sublists will be merged into one single list.
My code works fine when splitting is done twice. (eg.[3,6,8,5,2,1,4,7] -> [3,6,8],[5,2,1],[4,7] -> [3],[6],[8],[5],[2],[1],[4],[7]). But when the splitting is done more than twice, (eg,[3,6,8,5,2,1,4,7] -> [3,6,8,5],[2,1,4,7] -> [3,6],[8,5],[2,1],[4,7] -> [3],[6],[8],[5],[2],[1],[4],[7]), the code will fail. Can anyone help find me find out what goes wrong in my code? Thanks in advance.
I believe the problem you're having is that merge_sort sometimes returns a flattened list and other times returns a list of lists. You should probably return a flat list in all cases. There's some other cruft: You don't need split to be its own function, since you only call it the one time.
Here's a greatly simplified version of your code:
def merge_sort(lst, k):
if len(lst) == 1: # simpler base case
return lst
j = ceil(len(lst)/k) # no need to check for k < len(lst) (ceil handles it)
#split and recursively sort in one step
lst = [merge_sort(lst[i:i+j], k) for i in range(0, len(lst), j)]
return merge(lst) # always return a merged list (never a list of lists)

Resources