variable error in function while assignment - python

Write a Python script to sort (ascending and descending) a dictionary by value
def sort_dictionary_ascending(dict):
flag = True
list = []
while(len(dict)!=1):
flag = True
for x,y in dict.items():
if flag:
min = x
flag = False
elif min>x:
min =x;
list.append(min)
dict.pop(min)
min,value= dict.popitem()
list.append(min)
print(list)
def sort_dictionary_descending(dict):
flag = True
list = []
while(len(dict)!=1):
flag = True
for x,y in dict.items():
if flag:
max = x
flag = False
elif max < x:
max = x
list.append(max)
dict.pop(max)
max,value= dict.popitem()
list.append(max)
print(list)
d = {1: 1, 3: 3, 4: 4, 2: 2, 5: 5}
sort_dictionary_descending(d)
sort_dictionary_ascending(d)
Error is:
/home/admin2/Desktop/two/venv/bin/python /home/admin2/Desktop/two/sort_dictionary.py
Traceback (most recent call last):
File "/home/admin2/Desktop/two/sort_dictionary.py", line 45, in <module>
sort_dictionary_ascending(d)
File "/home/admin2/Desktop/two/sort_dictionary.py", line 17, in sort_dictionary_ascending
list.append(min)
UnboundLocalError: local variable 'min' referenced before assignment
[5, 4, 3, 2, 1]

First in your for loops use for x in dict.keys() instead of for x, y in dict.items()
because y variable isn't used in the whole loop. Second, I don't understand why you use a dict which the key is equal to the value, a list is more suitable

Related

Loops and Dictionary

How to loop in a list while using dictionaries and return the value that repeats the most, and if the values are repeated the same amount return that which is greater?
Here some context with code unfinished
def most_frequent(lst):
dict = {}
count, itm = 0, ''
for item in lst:
dict[item] = dict.get(item, 0) + 1
if dict[item] >= count:
count, itm = dict[item], item
return itm
#lst = ["a","b","b","c","a","c"]
lst = [2, 3, 2, 2, 1, 3, 3,1,1,1,1] #this should return 1
lst2 = [2, 3, 2, 2, 1, 3, 3] # should return 3
print(most_frequent(lst))
Here is a different way to go about it:
def most_frequent(lst):
# Simple check to ensure lst has something.
if not lst:
return -1
# Organize your data as: {number: count, ...}
dct = {}
for i in lst:
dct[i] = dct[i] + 1 if i in dct else 1
# Iterate through your data and create a list of all large elements.
large_list, large_count = [], 0
for num, count in dct.items():
if count > large_count:
large_count = count
large_list = [num]
elif count == large_count:
large_list.append(num)
# Return the largest element in the large_list list.
return max(large_list)
There are many other ways to solve this problem, including using filter and other built-ins, but this is intended to give you a working solution so that you can start thinking on how to possibly optimize it better.
Things to take out of this; always think:
How can I break this problem down into smaller parts?
How can I organize my data so that it is more useful and easier to manipulate?
What shortcuts can I use along the way to make this function easier/better/faster?
Your code produces the result as you describe in your question, i.e. 1. However, your question states that you want to consider the case where two list elements are co-equals in maximum occurrence and return the largest. Therefore, tracking and returning a single element doesn't satisfy this requirement. You need to compile the dict and then evaluate the result.
def most_frequent(lst):
dict = {}
for item in lst:
dict[item] = dict.get(item, 0) + 1
itm = sorted(dict.items(), key = lambda kv:(-kv[1], -kv[0]))
return itm[0]
#lst = ["a","b","b","c","a","c"]
lst = [2, 3, 2, 2, 2, 2, 1, 3, 3,1,1,1,1] #this should return 1
lst2 = [2, 3, 2, 2, 1, 3, 3] # should return 3
print(most_frequent(lst))
I edited the list 'lst' so that '1' and '2' both occur 5 times. The result returned is a tuple:
(2,5)
I reuse your idea which is quite neat, and I just modified your program a bit.
def get_most_frequent(lst):
counts = dict()
most_frequent = (None, 0) # (item, count)
ITEM_IDX = 0
COUNT_IDX = 1
for item in lst:
counts[item] = counts.get(item, 0) + 1
if most_frequent[ITEM_IDX] is None:
# first loop, most_frequent is "None"
most_frequent = (item, counts[item])
elif counts[item] > most_frequent[COUNT_IDX]:
# if current item's "counter" is bigger than the most_frequent's counter
most_frequent = (item, counts[item])
elif counts[item] == most_frequent[COUNT_IDX] and item > most_frequent[ITEM_IDX]:
# if the current item's "counter" is the same as the most_frequent's counter
most_frequent = (item, counts[item])
else:
pass # do nothing
return most_frequent
lst1 = [2, 3, 2, 2, 1, 3, 3,1,1,1,1, 2] # 1: 5 times
lst2 = [2, 3, 1, 3, 3, 2, 2] # 3: 3 times
lst3 = [1]
lst4 = []
print(get_most_frequent(lst1))
print(get_most_frequent(lst2))
print(get_most_frequent(lst3))
print(get_most_frequent(lst4))

how do I multiply integers in a set?

You are given a sequence of positive ints where every element appears three times, except one that appears only once (let's call it x) and one that appears only twice (let's call it y).
Your task is to find x * x * y.
e.g.
arr = [1,1,1,2,2,2,3,3,4] -> 4 x 4 x 3
I have written some code below. I have a question regarding the final part of the code- so after the completion of the loop, there should be one integer left in seen_once and one integer left in seen_twice, but how do I then multiply these numbers, as they are now sitting in a set()?
def Missing_Values(arr):
seen_once = set()
seen_twice = set()
seen_thrice = set()
for i in arr:
if i not in seen_once or seen_twice or seen_thrice:
seen_once.add(i)
elif i in seen_once:
seen_twice.add(i)
seen_once.remove(i)
elif i in seen_twice:
seen_thrice.add(i)
seen_twice.remove(i)
return seen_once*seen_once*seen_twice
Missing_Values(arr)
One way would be to pop the values.
x = seen_once.pop()
y = seen_twice.pop()
return x * x * y
You can use counter from collections for better performance that also improves readability.
Following is the code:
from collections import Counter
arr = [1, 1, 1, 2, 2, 2, 3, 3, 4]
d = Counter(arr)
ans = 1
for x, cnt in d.items():
if cnt == 2:
ans *= x
elif cnt == 1:
ans *= (x * x)
print(ans)
You can also use list comprehension as a generator as follows:
from collections import Counter
arr = [1, 1, 1, 2, 4, 4, 3, 3, 4]
d = Counter(arr)
x, y = (x**(3 - cnt) for x, cnt in d.items() if(cnt <= 2))
print(x*y)
Counter Explanation:
Counter returns a dictionary where array item as a Key and item frequency as a value. For example, if array arr = [1, 1, 1, 2, 2, 2, 3, 3, 4] then counter provide following dictionary:
d = {
1: 3,
2: 3,
3: 2,
4: 1
}
You have a bug in your code, this is a working piece:
def Missing_Values(arr):
seen_once = set()
seen_twice = set()
seen_thrice = set()
for i in arr:
if i not in seen_once and i not in seen_twice and i not in seen_thrice: # Note this line!
seen_once.add(i)
elif i in seen_once:
seen_twice.add(i)
seen_once.remove(i)
elif i in seen_twice:
seen_thrice.add(i)
seen_twice.remove(i)
return next(iter(seen_once))*next(iter(seen_once))*next(iter(seen_twice))
arr = [1,1,1,2,2,2,3,3,4]
print(Missing_Values(arr))

creating a list using a function from an undefined list

I'm asked to create a list of numbers that stops when the number 7 appears.
I've tried the following, but get a runtime error:
def sublist(x):
s = []
while x != 7:
s.append(x)
return s
Any ideas?
If you're getting a runtime error, you probably cannot compare the type of x to 7. Try
def sublist(x):
s = []
for elem in x:
if elem != 7:
s.append(elem)
else:
break
return s
This will only work if x is iterable and has elements that can be compared to 7.
Try this,
def sublist(x):
s = []
x1=0 #initialized x1
while x[x1] != 7:
s.append(x[x1])
if x1==len(x)-1:
break
x1+=1 #increment x1
return s
x=[1,4,8,9,2,7,4,2,3,4]
print(sublist(x))
output:
[1, 4, 8, 9, 2, 4, 2, 3, 4]
Hope this helps you!

'int' object is not subscriptable?

I'm doing an algorithm challenge on www.edabit.com, where you have a list of dice rolls, and:
if the number is 6, the next number on the list is amplified by a factor of 2
if the number is 1, the next number on the list is 0
this is my code:
def rolls(lst):
out = 0
iterate = 0
if lst[iterate] == 1:
out+=lst[iterate]
lst[iterate+1] = 0
iterate+=1
rolls(lst[iterate])
elif lst[iterate] == 6:
out+=lst[iterate]
lst[iterate+1] = lst[iterate+1]*2
iterate+=1
rolls(lst[iterate])
else:
out+=lst[iterate]
iterate+=1
The console gives me "TypeError: 'int' object is not subscriptable"
Any ideas? Also any other errors you spot would be useful.
I tried on other IDE's, but it gives the same output.
for a series like "1, 6, 2, 3, 2, 4, 5, 6, 2" I expect 27
As stated in the comments, for this kind of problem I wouldn't use recursion. A loop will be enough:
l = [1, 6, 2, 3, 2, 4, 5, 6, 2]
from itertools import accumulate
print(sum(accumulate([0] + l, lambda a, b: b*{1:0, 6:2}.get(a, 1))))
Prints:
27
If you have to use recursion for this problem, then you will need to pass two arguments first lst and second iterate. Note that lst[iterate] is a single element which you are passing to the function when calling it recursively.
Thus modify the function to take two arguments lst and iterate. And initially pass arguments as full list for lst and a 0 for iterate. rolls(lst, 0) should be your initial function call.
I suppose you want out variable to contain sum of all entries in lst when you visit them, so that also needs to be passed as an argument, making your initial call rolls(lst, 0, 0). I have edited the function to return the sum calculated in out accordingly.
def rolls(lst, iterate, out):
if iterate == len(lst):
return out
if lst[iterate] == 1:
out += lst[iterate]
if iterate + 1 < len(lst): #In order to avoid index out of bounds exception
lst[iterate + 1] = 0
rolls(lst, iterate + 1, out)
elif lst[iterate] == 6:
out += lst[iterate]
if iterate + 1 < len(lst): #In order to avoid index out of bounds exception
lst[iterate + 1] = lst[iterate + 1] * 2
rolls(lst, iterate + 1, out)
else:
out += lst[iterate]
rolls(lst, iterate+1, out)
Instead of looking to the next item, you can look at the previous item:
from itertools import islice
def rolls(lst):
if not lst:
return 0
total = prev = lst[0]
for x in islice(lst, 1, None):
if prev == 1:
x = 0
elif prev == 6:
x *= 2
prev = x
total += x
return total
For example:
>>> rolls([1, 6, 2, 3, 2, 4, 5, 6, 2])
27
>>> rolls([])
0
>>> rolls([1])
1
>>> rolls([2])
2
>>> rolls([3])
3
>>> rolls([4])
4
>>> rolls([6,1])
8
>>> rolls([6,2])
10
>>> rolls([6,1,5])
13

duplicates function, adding

Hello I am trying to develop a function to find duplicates in a list. Below is the code that I have obtained thus far. I am cannot seem to figure out how to get the code to correctly add the number of duplicated numbers.
import collections
myList = [5, 9, 14, 5, 2, 5, 1]
def find_duplicates(aList, target):
if target not in aList:
print (target, "occurred 0 times")
else:
n=0
print (target, "occurred",n+1,"times")
the output of the code shows:
find_duplicates(myList, 5)
5 occurred 1 times
Obviously I am missing something for the program to properly track how many times the value occurs? Can someone please help?
I am not allowed to use the count() or sort() built in functions.
To only count the number of duplicates, just iterate over the list, comparing each value. If you find a match, increment a counter, than report the counter. To make this better, I would return the count then print to console outside of the def.
import collections
def find_duplicates(aList, target):
n = 0
for obj in aList:
if obj is target:
n += 1
return n
myList = [5, 9, 14, 5, 2, 5, 1]
target = 5
num_dup = find_duplicates(myList, target)
print (target, "occurred", num_dup, "times")
This should echo out:
5 occurred 3 times
Or do this (with list.count(x)):
myList = [5, 9, 14, 5, 2, 5, 1]
target = 5
num_dup = myList.count(target)
print (target, "occurred", num_dup, "times")
This should echo out:
5 occurred 3 times
You forgot to increment n in your code, so it always print 1. I think your code should look like:
import collections
myList = [5, 9, 14, 5, 2, 5, 1]
def find_duplicates(aList, target):
if target not in aList:
print (target, "occurred 0 times")
else:
n= aList.count(5)
print (target, "occurred",n,"times")
without using count and reading the target from shell:
import collections
myList = [5, 9, 14, 5, 2, 5, 2]
def find_duplicates(aList, target):
result = 0
for item in aList:
if item == target:
result += 1
return result
try:
target = int(raw_input("Choose a number to find duplicates: ")) # for python 3.X use input instead of raw_input
res = find_duplicates(myList, target)
print (target, " occurred ", res, " times")
except:
print("Write a number, not anything else")
This works for integers, if you want to use floats, just change int(...) for float(...)
it's a simple case of using a dictionary. Check the following code:
def frequency(l):
counter = {}
for x in l:
counter[x] = counter.get(x, 0) + 1
return counter
It will iterate over the list, saving each element as a key to the counter dictionary. Note the special form counter.get(x, 0), it will return the value of counter[x] if x is already on the dict, else it will return zero.
Checking the results is a matter of using:
print(frequency(myList))
>>> {9: 1, 2: 1, 5: 3, 14: 1, 1: 1}
You can get the number of appearances of any member by inspecting the dictionary:
frq = frequency(myList)
print(frq[14])
>>> 1
print(frq[1])
>>> 1
Of course it's possible to write a wrapper:
def target_frequencty(target, my_list):
frq = frequencty(my_list)
return frq.get(target, 0)
Enjoy.

Categories