Screening for duplicates in a tuple - Python - python-3.x

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

Related

Two Sum function not working with recurring elements in list

I'm trying to complete "Two Sum", which goes as such:
Write a function that takes an array of numbers (integers for the tests) and a target number. It should find two different items in the array that, when added together, give the target value. The indices of these items should then be returned in a tuple like so: (index1, index2).
Efficiency of my code aside, this is what I have so far:
def two_sum(numbers, target):
for i in numbers:
for t in numbers:
if i + t == target:
if numbers.index(i) != numbers.index(t):
return (numbers.index(i), numbers.index(t))
return False
It works for inputs such as:
>>> two_sum([1,2,3,4,5,6,7,8,9,10], 11)
(0, 9)
But when I try a list of numbers that have recurring numbers that add up to the target, the code doesn't work:
>>> two_sum([2, 2], 4)
False
The code, for some reason that I cannot figure out, does not reach index [1] of the list, and thus returns False.
Why is that?
The list method index() always returns the first occurence of an item in a list, so numbers.index(i) != numbers.index(t) evaluates to 1 != 1 which is False.
You should use the builtin enumerate() to store the indices while looping over the list.
def two_sum(numbers, target):
for i, number_a in enumerate(numbers):
for j, number_b in enumerate(numbers):
if number_a + number_b == target and i != j:
return (i, j)
return False
'''
return will break the loop and come out of function, so first you need to complete the cycle, store the result in list as you cant write to tuple,
once your loop gets completed convert list to tuple and return
'''
def two_sum(numbers, target):
result = []
for i in numbers:
for t in numbers:
if (i + t == target) and (numbers.index(i) != numbers.index(t)):
result.append(i)
result.append(t)
if (len(result)> 0):
return tuple(result)
else:
return False
Your code looks fine except this part:
if numbers.index(i) != numbers.index(t):
return (numbers.index(i), numbers.index(t))
return False
Because the index method returns only the first occurrence of a value, i and t are always the same. It will always return false. The index of the value 2 is always 0 in the list even though there is another 2 at index 1.
Source: https://www.w3schools.com/python/ref_list_index.asp
What you want to do is this:
def two_sum(numbers, target):
i_index = 0
t_index = 0
for i in numbers:
for t in numbers:
if i + t == target:
if i_index != t_index:
return (i_index, t_index)
t_index +=1
i_index +=1
return False
This way the index is not associated with the value
def pairs_sum_to_target(list1, list2, target):
'''
This function is about a game: it accepts a target integer named target and
two lists of integers (list1 and list2).
Then this function should return all pairs of indices in the form [i,j]
where list1[i] + list[j] == target.
To summarize, the function returns the pairs of indices where the sum of
their values equals to target.
Important: in this game list1 and list2 will always have the same number of
elements and returns the pairs in that order.
'''
pairs = [] #make a list, which is empty in the beginning. But store the sum pairs == target value.
#loop for all indices in list1 while looping all the same indices in list2 and comparing if the sum == target variable.
for i, value1 in enumerate (list1):
for j, value2 in enumerate(list2):
if value1 + value2 == target: ## if the value of element at indice i + value of element at indice j == target, then append the pairs to list pairs []- in order.
pairs.append(i,j)
return pairs
Simple Input #1
"""This is one example of input for list1, list2, and target. In order to properly test this function"""
list1 = [1,-2,4,5,9]
list2 = [4,2,-4,-4,0]

Comparing the lengths of lists with list comprehension Python

I am trying to write a list comprehension function that checks the length of each lists val..val6 within the nested list functions storage..storage4 to see if all the lists values lengths are greater than 0. Then returns a bool value if satisfies. So in storage val2 has a length greater than 0 and so do all the other lists except for val, since not all the lists in storage have a length greater than 0 it will output False. storage4 satisfies the condition where all the lists lengths are greater than 0 so it outputs True. How would I be able to modify the code to get the expected output?
val = []
val2 = [12,456,786,9]
val3 = [556]
val4 = [66,7,4,3,12]
val5 = [99,88,6]
val6 = [12,4567]
storage = [val,val2,val3]
storage2 = [val,val2,val3,val4,val5,val6]
storage3 = [val,val2,val4,val6]
storage4 = [val2,val5,val6]
def checking(list_val):
newlist = [True for x in list_val if len(x) > 0]
print(checking(storage))
print(checking(storage2))
print(checking(storage3))
print(checking(storage4))
Output
None
None
None
None
Expected Output:
False
False
False
True
The reason you are getting None because your function didn't return anything. Even if you return newlist, it will still not work as newlist is a list containing either True values or empty.
This can be done like below with help of all() and a generator expression -
def checking(list_val):
return all(len(x) > 0 for x in list_val)
Here the generator expression will loop over all element in list_val and checks whether the length of the element is greater than 0. all() will check if all the elements produced by generator is True or not.
Another approach would be as #Lumorti mentioned, is to loop over and check if any sublist length is 0 and return immediately.
Firstly, the reason it's giving "None" is because you need a return statement in the function, currently the function doesn't return anything.
Here's an implementation that works, although it doesn't use a list comprehension since those are more for creating new lists rather than a single output:
val = []
val2 = [12,456,786,9]
val3 = [556]
val4 = [66,7,4,3,12]
val5 = [99,88,6]
val6 = [12,4567]
storage = [val,val2,val3]
storage2 = [val,val2,val3,val4,val5,val6]
storage3 = [val,val2,val4,val6]
storage4 = [val2,val5,val6]
def checking(list_val):
for x in list_val:
if len(x) == 0:
return False
return True
print(checking(storage))
print(checking(storage2))
print(checking(storage3))
print(checking(storage4))
Here it checks each element, if the length of the element is zero then it stops and returns False, otherwise it eventually returns True once it has checked everything.

Mark Element in List

I have an excercise about prime numbers that requires me to write a function which takes a list of elements and a number p and marks elements False which are in the range 2p, 3p...N
First I create a list of True and False:
true_value = [False, False] + [True for x in range(n-1)] #Let assumme that n=16
And then I write the function that find the even number in this list (with p = 2)
def mark_false(bool_list, p):
range_new = [x for x in range(len(bool_list))]
for i in range(2, len(range_new)):
for j in range(p, len(range_new), p):
if (i*p == range_new[j]) & (i*p <= len(range_new)):
bool_list[j] = False
return bool_list
This function help me to find the location of the even number (>2) and return to False
Example: a = list_true(16)
a = [False,False,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True]
b = mark_false(a, 2)
b = [False,False,True,True,False,True,False,True,False,True,False,True,False,True,False,True]
This function mark_false does work but the problem is everytime I run it I have to create a list range_new which takes a lot of time to calculate. So how do I rewrite this function so it can run faster without creating new lists?
You seem to be doing things the long way around, searching for the j value that matches the multiple of p you want to set to False. But since you already know that value already, there's no need to search for it, just set it directly.
I'd do:
def mark_false(bool_list, p):
for i in range(p, len(bool_list), p): # p, 2*p, 3*p, ...
bool_list[i] = False # do the assignment unconditionally
You probably shouldn't need a return statement, since you're modifying the list you are passed in-place. Returning the list could make the API misleading, as it might suggest that the returned list is a new one (e.g. a modified copy).
If you did want to return a new list, you could create one with a list comprehension, rather than modifying the existing list:
def mark_false_copy(bool_list, p):
return [x if i % p else False for i, x in enumerate(bool_list)]

How to apply multiprocessing in python3.x for the following nested loop

for i in range(1,row):
for j in range(1,col):
if i > j and i != j:
x = Aglo[0][i][0]
y = Aglo[j][0][0]
Aglo[j][i] = offset.myfun(x,y)
Aglo[i][j] = Aglo[j][i]
Aglo[][] is a 2D array, which consists of lists in the first row
offset.myfun() is a function defined elsewhere
This might be a trivial question but i couldn't understand how to use multiprocessing for these nested loops as x,y (used in myfun()) is different for each process(if multiprocessing is used)
Thank you
If I'm reading your code right, you are not overwriting any previously calculated values. If that's true, then you can use multiprocessing. If not, then you can't guarantee that the results from multiprocessing will be in the correct order.
To use something like multiprocessing.Pool, you would need to gather all valid (x, y) pairs to pass to offset.myfun(). Something like this might work (untested):
pairs = [(i, j, Aglo[0][i][0], Aglo[j][0][0]) for i in range(1, row) for j in range(1, col) if i > j and i != j]
# offset.myfun now needs to take a tuple instead of x, y
# it additionally needs to emit i and j in addition to the return value
# e.g. (i, j, result)
p = Pool(4)
results = p.map(offset.myfun, pairs)
# fill in Aglo with the results
for pair in pairs:
i, j, value = pair
Aglo[i][j] = value
Aglo[j][i] = value
You will need to pass in i and j to offset.myfun because otherwise there is no way to know which result goes where. offset.myfun should then return i and j along with the result so you can fill in Aglo appropriately. Hope this helps.

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