How can I count all deleted elements when I remade the list into a set(Python) - python-3.x

I need to make a function, which will take a list or tuple and remade it into a set. As there are no duplicate elements in the set, I need to write the number of all deleted elements. This is my code,
def find_type(arg):
if isinstance(arg, list):
arg = set(arg)
return arg
elif isinstance(arg, tuple):
a = list(arg)
return set(a)
print(find_type((1, 2, 2, 3)))
and answer
{1, 2, 3}
The function works, so i just do not know how to count and write the number of deleted elements

You can use the following relation:
number1 = len(arg)
number2 = len(find_type(arg))
number = number1-number2

Number of deleted elements is simply the difference in length of list/tuple and set.
Also, you don't need to check if arg is instance of list or tuple (and even if you do, do it in one conditional). set accepts all iterable types (like lists, tuples, strings, etc.).

Related

How to subtract adjacent items in list with unknown length (python)?

Provided with a list of lists. Here's an example myList =[[70,83,90],[19,25,30]], return a list of lists which contains the difference between the elements. An example of the result would be[[13,7],[6,5]]. The absolute value of (70-83), (83-90), (19-25), and (25-30) is what is returned. I'm not sure how to iterate through the list to subtract adjacent elements without already knowing the length of the list. So far I have just separated the list of lists into two separate lists.
list_one = myList[0]
list_two = myList[1]
Please let me know what you would recommend, thank you!
A custom generator can return two adjacent items at a time from a sequence without knowing the length:
def two(sequence):
i = iter(sequence)
a = next(i)
for b in i:
yield a,b
a = b
original = [[70,83,90],[19,25,30]]
result = [[abs(a-b) for a,b in two(sequence)]
for sequence in original]
print(result)
[[13, 7], [6, 5]]
Well, for each list, you can simply get its number of elements like this:
res = []
for my_list in list_of_lists:
res.append([])
for i in range(len(my_list) - 1):
# Do some stuff
You can then add the results you want to res[-1].

I want to arrange the list of strings with a certain condition

I want to arrange the list of strings alphabetically but with the condition that strings that start with x go first. For example, the input is list=['apple','pear','xanadu','stop'].
I'm sure you need to add some condition at the sort function but I'm not sure what to put.
list2=[]
string=input("Enter a string:")
list2.append(string)
while string!="stop":
string=input("Enter a string:")
list2.append(string)
list2.remove("stop")
print("Your list is:",list2)
print("Sorted list:",sorted(list2))
I want the output to be list=['xanadu','apple','pear']. I removed the 'stop' btw.
Use the key function that will determine the ordering of elements:
>>> sorted(['apple','pear','xanadu','stop'], key=lambda val: (0, val) if val.startswith('x') else (1, val))
['xanadu', 'apple', 'pear', 'stop']
The lambda means the following:
lambda val:\ # determine the ordering of the element `val`
(0, val)\ # make the algorithm compare tuples!
if val.startswith('x')\
else (1, val) # use default alphabetical ordering otherwise
Since we're now comparing tuples (but ordering the actual values), tuples whose first element is zero will always sort as being greater than those whose first element is 1.

Deleted list entries returning?

tl;dr: how can i delete duplicates from one list, while deleting corresponding entries in a different list?
(note that "class" here is not a class in the programming sense, but in the Dungeons and Dragons sense)
I'm trying to make a function that takes in a list of weights and returns a list of associated strings a number of times equal to the weight. I use random.choice to then select one of these items at random. Here I am removing weights due to multiple possible ways to qualify for each class (multiclassing rules in D&D).
However, I'm running into an error (IndexError: list index out of range) when I try to run this part of the code:
def makeRollable(weights, classNames):
output = []
classNames, weights2 = removeDuplicates(classNames, weights)
for i in range(0, len(weights2)):
weight = weights2[i]
for j in range(0, weight):
output.append(classNames[i])
return output
def removeDuplicates(names, weights):
for i in range(len(names)-1, 0, -1):
for j in range(len(names)-1, i, -1):
if names[i] == names[j]:
weights[i] = max(weights[i], weights[j])
del names[j]
del weights[j]
names2, weights2 = names, weights
return names2, weights2
When I run in debugger, I see that even though the names2 and weights2 have fewer entries in the removeDuplicates fuction, the weights2 list returned to the original size of weights in the makeRollable function.
while the names list has had 5 entries deleted (it was supposed to), the weights list did not. Given that I'm deleting names and weights entries at the same time, I don't see why this should be.
I thought it might be something to do with returning a variable of the same name as one passed to the function, so I made the names2 and weights2 variables to try to fix that, but it didn't seem to help. I was getting the same error with them removed.
if it's helpful, here is a sample data set (there are duplicates for the fighter, magus, and shaman classes because you can qualify for them based on different criteria, and the easiest way I could think of to check for that was to add them multiple times, and then just keep the maximum weight):
classNames = ['Barbarian', 'Bard', 'Cleric', 'Druid', 'Fighter', 'Fighter', 'Mage', 'Magus', 'Magus', 'Magus', 'Monk', 'Paladin', 'Ranger', 'Rogue', 'Shaman', 'Shaman', 'Shaman', 'Sorcerer', 'Warlock', 'Wizard']
weights = [4, 2, 0, 0, 4, 0, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 2, 0]
Since you've validated that your function is returning the right value, and the other function is not receiving the right input, I think the issue is on how you're dealing with the lists between these functions.
Specifically, you're probably returning a value at some point, but not overwriting the two lists. Basically something like:
a = []
b = []
a = populate_a(a)
b = populate_b(b)
removeDupes(a, b)
# should be
# a, b = removeDupes(a,b)
makeRollable(a, b)
A better long term solution would be to use a dictionary, or if you absolutely need two lists write a class to complete your required functionalities with the two lists. Then just pass this object around and manipulate in the functions using its basic modifiers.

Recursion happens too many times and list is not iterable

I'm trying to make a secret santa programm. The input is in form of the list of names of people g. ["John", "Bob", "Alice"] and the list of emials ["John#gmail.com", "Bob#gmail.com", "Alice#outlook.com"]. I need to generate pairs of email adress and a random name which doesn't belong to the said email adress. For this I have written the function compare.
def compare(list_of_names, list_of_emails):
zipped_lists = zip(list_of_emails, list_of_names)
random.shuffle(list_of_emails)
zipped_shuffled_lists = zip(list_of_emails, list_of_names)
for pair in zipped_lists:
for shuffle_pair in zipped_shuffled_lists:
if shuffle_pair == pair:
return compare(list_of_names, list_of_emails)
return zipped_shuffled_lists
But instead of shuffling like it should it just creates a recursion. i still can't find out why. After a finite amount of time it should create two different lists that work. Also the shuffled_list_of_emails is not iterable, why?
EDIT:changed the code with shuffle because it works in place
zip is lazy!
I'm not sure why, but I'm too excited about this right now, so the answer might be a bit messy. Feel free to ask for clarification)
Let's step through your code:
def compare(list_of_names, list_of_emails):
# the `zip` object doesn't actually iterate over any of its arguments until you attempt to iterate over `zipped_lists`
zipped_lists = zip(list_of_emails, list_of_names)
# modify this IN-PLACE; but the `zip` object above has a pointer to this SAME list
random.shuffle(list_of_emails)
# since the very first `zip` object has `list_of_emails` as its argument, AND SO DOES THE ONE BELOW, they both point to the very same, SHUFFLED (!) list
zipped_shuffled_lists = zip(list_of_emails, list_of_names)
# now you're iterating over identical `zip` objects
for pair in zipped_lists:
for shuffle_pair in zipped_shuffled_lists:
# obviously, this is always true
if shuffle_pair == pair:
# say "hello" to infinite recursion, then!
return compare(list_of_names, list_of_emails)
return zipped_shuffled_lists
Let's recreate this in the Python interpreter!
>>> List = list(range(5))
>>> List
[0, 1, 2, 3, 4]
>>> zipped_1 = zip(List, range(5))
>>> import random
>>> random.shuffle(List)
>>> zipped_2 = zip(List, range(5))
>>> print(List)
[4, 2, 3, 0, 1]
>>> zipped_1, zipped_2 = list(zipped_1), list(zipped_2)
>>> zipped_1 == zipped_2
True
You see, two different zip objects applied to the same list at different times (before and after that list is modified in-place) produce the exact same result! Because zip doesn't do the zipping once you do zip(a, b), it will produce the zipped... uh, stuff... on-the-fly, while you're iterating over it!
So, to fix the issue, do not shuffle the original list, shuffle its copy:
list_of_emails_copy = list_of_emails.copy()
random.shuffle(list_of_emails_copy)
zipped_shuffled_lists = zip(list_of_emails_copy, list_of_names)
There's correct answer from #ForceBru already. But a will contribute a little.
You should avoid zip's lazy evaluation and unfold zips with, for example, list:
def compare(list_of_names, list_of_emails):
zipped_lists = list(zip(list_of_emails, list_of_names)) # eager evaluation instead of lazy
random.shuffle(list_of_emails) # shuffle lists
zipped_shuffled_lists = list(zip(list_of_emails, list_of_names)) # eager again
for pair in zipped_lists:
for shuffle_pair in zipped_shuffled_lists:
if shuffle_pair == pair:
return compare(list_of_names, list_of_emails)
return zipped_shuffled_lists
But I guess you need no recursion and can achieve your task easier:
def compare(list_of_names, list_of_emails):
zipped_lists = list(zip(list_of_emails, list_of_names))
random.shuffle(zipped_lists) # shuffle list of emails and names
result = []
shuffled_emails = [i[0] for i in zipped_lists]
for i, _ in enumerate(shuffled_emails):
result.append(zipped_lists[i-1][1]) # shift email relatively one position to the right
return list(zip(result, shuffled_emails))
This code links an name with an email of a previous name, which is randomly selected, and it guaranteed does not match.
There's no recursion, works fine for lists with two or more elements.

Python- How to fix failed testcase on a has repeat function?

I've built a function that checks for repeats of a specific number in a list named xs. V is the number to check for repeats of. It needs to return True if there are more than one occurrences of the number and if there are none, it needs to return False.
I'm failing one test case which is input xs=[1,2,1] v=1, this function needs to return True, but my code is making it False. Can you see where I went wrong?
Here is my current code:
def has_repeat(xs, v):
count=0
for num in range(len(xs)):
if num == v:
count+=1
if count>1:
return True
else:
return False
You're actually iterating over the range of the length of the list, not the items in the list.
The range function returns a list of numbers from 0 (by default) to the number you provide, in this case 3 (not inclusive). See Python documentation.
As an example if you try:
l = [1, 2, 3]
print(range(len(l)))
It will print out [0, 1, 2]
What you should do is instead of
for num in range(len(xs))
do
for num in xs:
You can try it out on PyFiddle here
As an added tasty bonus, you could change this to use the .count method on your list of items to check how many occurrences of that number are in the list, removing the need to iterate the list at all, like so:
count = xs.count(v)

Resources