Related
I am having several python errors in this code and I need help with the code. I'm fairly new to python so I have trouble figuring this out.
Traceback (most recent call last):
File "/root/sandbox/stats.py", line 74, in <module>
main()
File "/root/sandbox/stats.py", line 66, in main
"Mean of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]: ", mean(range(1, 11))
File "/root/sandbox/stats.py", line 25, in mean
list.range()
AttributeError: 'range' object has no attribute 'range'
this is the error I keep getting.
This is my code
def median(list):
if len(list) == 0:
return 0
list.sort()
midIndex = len(list) / 2
if len(list) % 2 == 1:
return list[midIndex]
else:
return (list[midIndex] + list[midIndex - 1]) / 2
def mean(list):
if len(list) == 0:
return 0
list.range()
total = 0
for number in list:
total += number
return total / len(list)
def mode(list):
numberDictionary = {}
for digit in list:
number = numberDictionary.get(digit, None)
if number is None:
numberDictionary[digit] = 1
else:
numberDictionary[digit] = number + 1
maxValue = max(numberDictionary.values())
modeList = []
for key in numberDictionary:
if numberDictionary[key] == maxValue:
modeList.append(key)
return modeList
def main():
print
"Mean of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]: ", mean(range(1, 11))
print
"Mode of [1, 1, 1, 1, 4, 4]:", mode([1, 1, 1, 1, 4, 4])
print
"Median of [1, 2, 3, 4]:", median([1, 2, 3, 4])
main()
I don't know how to actually fix it.
I've tried to quick fix and replaced == with the is operator but nothing worked
When you print something make sure you are using opening brackets:
print("Mean of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]: ", mean(list(range(1,11))))
# print("Mode of [1, 1, 1, 1, 4, 4]:", mode([1, 1, 1, 1, 4, 4]))
print("Median of [1, 2, 3, 4]:", median([1, 2, 3, 4, 5]))
In order to make your median code working you should cast the midIndex to integer type:
midIndex = int(len(list) / 2)
I rewrote you mean function a bit:
def mean(list):
length = len(list)
if length == 0:
return 0
else:
sum = 0
for n in list:
sum += n
return sum / length
I called this function with a list made with range:
list(range(1,11))
I am not sure what you want to achieve with your mode function. But perhaps you have had some help now to try this one yourselve.
Happy coding!
list.range()
modify
range(list.start,list.stop,list.step)
len(list) / 2 is float
midIndex = len(list) / 2
modify
midIndex = math.ceil(len(list) / 2)
enter image description here
Given that I have a list of numbers:
raw_list = [10, 9, 2, 8, 1, 3, 5, 4, 6, 7,11]
I want to separate it to top N's three times. Which means I want to rank them.
# Top 6 rank as 3
# Next Top 4 rank as 2
# Last Top 1 rank as 1
ranked_list = [3, 3, 2, 3, 1, 2, 2, 2, 3, 3, 3]
What I tried:
sorted(range(len(raw_list)), key=lambda i: raw_list[i])[-2:]
But this only gives indeces of the topmost and not the next topmost value of the list.
Use:
lst = [10, 9, 2, 8, 1, 3, 5, 4, 6, 7, 11]
indices = sorted(range(len(lst)), key=lambda i: lst[i], reverse=True)
ranked_list = [0 for _ in range(len(lst))]
for i, j in enumerate(indices):
if i < 6:
ranked_list[j] = 3
elif i < 6 + 4:
ranked_list[j] = 2
else:
ranked_list[j] = 1
print(ranked_list)
Output
[3, 3, 2, 3, 1, 2, 2, 2, 3, 3, 3]
Here's a different approach which is significantly faster than the accepted answer (if that's important):
Edited to show performance timings between the original and accepted answer because #funnydman wants proof
from timeit import timeit
L = [10, 9, 2, 8, 1, 3, 5, 4, 6, 7, 11]
def func1(list_):
slist = sorted(list_)
result = []
top6 = set(slist[5:])
top4 = set(slist[1:5])
for e in list_:
if e in top6:
result.append(3)
elif e in top4:
result.append(2)
else:
result.append(1)
return result
def func2(list_):
indices = sorted(range(len(list_)), key=lambda i: list_[i], reverse=True)
ranked_list = [0 for _ in range(len(list_))]
for i, j in enumerate(indices):
if i < 6:
ranked_list[j] = 3
elif i < 6 + 4:
ranked_list[j] = 2
else:
ranked_list[j] = 1
return ranked_list
for func in func1, func2:
print(func.__name__, timeit(lambda: func(L)))
Output:
func1 1.3904414890002954
func2 2.388311982000232
IIUC, this will work for you:
import pandas as pd
list(pd.cut(l, bins=[0, 1, 5, 11], labels=[1, 2, 3]))
Output:
[3, 3, 2, 3, 1, 2, 2, 2, 3, 3, 3]
In the following code, I call the Sort function two times with a different behavior but it returns the same results. In the advancedSort() function, I called Sort() function two times with different behavior (order) and saved each result in different lists but when I am printing the lists the results are the same!
def Sort(inputs, order = "ascending"):
if order == "ascending":
for i in range(len(inputs)):
for j in range(i + 1, len(inputs)):
if inputs[i] > inputs[j]:
inputs[i], inputs[j] = inputs[j], inputs[i]
elif order == "decending":
for i in range(len(inputs)):
for j in range(i + 1, len(inputs)):
if inputs[i] < inputs[j]:
inputs[i], inputs[j] = inputs[j], inputs[i]
else:
raise ValueError(order)
return inputs
def advancedSort(inputList, inputOrder):
if inputOrder == "ascending":
newList = Sort(inputList, "ascending")
return newList
elif inputOrder == "decending":
newList = Sort(inputList, "decending")
return newList
elif inputOrder == "both":
newList1 = Sort(inputList, "ascending")
newList2 = Sort(inputList, "decending")
return newList1, newList2
else:
raise ValueError(order)
a = [1, 4, 7, 7, 0, 6, 4]
print(a)
b, c = advancedSort(a, "both")
print(b)
print(c)
Output is:
[1, 4, 7, 7, 0, 6, 4]
[7, 7, 6, 4, 4, 1, 0]
[7, 7, 6, 4, 4, 1, 0]
When Sort() runs the first time it'll change the list referenced by a.
When you run it a second time, it's not using the original list you've defined in the beginning, but one already modified by Sort().
To address this you may use a shallow copy of the list:
newList1 = Sort(inputList.copy(), "ascending")
newList2 = Sort(inputList.copy(), "decending")
I used your code to print the memory address of each variable and their behavior in the routines:
def Sort(inputs, order = "ascending"):
if order == "ascending":
print(f"running the ascending routine with inputs = {inputs} ({hex(id(inputs))})")
for i in range(len(inputs)):
for j in range(i + 1, len(inputs)):
if inputs[i] > inputs[j]:
inputs[i], inputs[j] = inputs[j], inputs[i]
elif order == "decending":
print(f"""running the decending routine with inputs = {inputs} ({hex(id(inputs))})""")
for i in range(len(inputs)):
for j in range(i + 1, len(inputs)):
if inputs[i] < inputs[j]:
inputs[i], inputs[j] = inputs[j], inputs[i]
else:
raise ValueError(order)
return inputs
def advancedSort(inputList, inputOrder):
if inputOrder == "ascending":
newList = Sort(inputList, "ascending")
return newList
elif inputOrder == "decending":
newList = Sort(inputList, "decending")
return newList
elif inputOrder == "both":
newList1 = Sort(inputList, "ascending")
newList2 = Sort(inputList, "decending")
return newList1, newList2
elif inputOrder == "shallow":
newList1 = Sort(inputList.copy(), "ascending")
newList2 = Sort(inputList.copy(), "decending")
return newList1, newList2
else:
raise ValueError(order)
a = [1, 4, 7, 7, 0, 6, 4]
print(f"a = {a} ({hex(id(a))})")
print("\ntrying shallow mode")
b, c = advancedSort(a, "shallow")
print(f"b = {b} ({hex(id(b))})")
print(f"c = {c} ({hex(id(c))})")
print("\ntrying both mode")
d, e = advancedSort(a, "both")
print(f"a = {a} ({hex(id(a))})")
print(f"d = {d} ({hex(id(d))})")
print(f"e = {e} ({hex(id(e))})")
print("\nnow trying shallow mode again")
f, g = advancedSort(a, "shallow")
print(f"a = {a} ({hex(id(a))})")
print(f"f = {f} ({hex(id(f))})")
print(f"g = {g} ({hex(id(g))})")
Output:
a = [1, 4, 7, 7, 0, 6, 4] (0x7f4166c71240)
trying shallow mode
running the ascending routine with inputs = [1, 4, 7, 7, 0, 6, 4] (0x7f4166a535c0)
running the decending routine with inputs = [1, 4, 7, 7, 0, 6, 4] (0x7f4166ac8a80)
b = [0, 1, 4, 4, 6, 7, 7] (0x7f4166a535c0)
c = [7, 7, 6, 4, 4, 1, 0] (0x7f4166ac8a80)
trying both mode
running the ascending routine with inputs = [1, 4, 7, 7, 0, 6, 4] (0x7f4166c71240)
running the decending routine with inputs = [0, 1, 4, 4, 6, 7, 7] (0x7f4166c71240)
a = [7, 7, 6, 4, 4, 1, 0] (0x7f4166c71240)
d = [7, 7, 6, 4, 4, 1, 0] (0x7f4166c71240)
e = [7, 7, 6, 4, 4, 1, 0] (0x7f4166c71240)
now trying shallow mode again
running the ascending routine with inputs = [7, 7, 6, 4, 4, 1, 0] (0x7f4166ac88c0)
running the decending routine with inputs = [7, 7, 6, 4, 4, 1, 0] (0x7f4166ac8780)
a = [7, 7, 6, 4, 4, 1, 0] (0x7f4166c71240)
f = [0, 1, 4, 4, 6, 7, 7] (0x7f4166ac88c0)
g = [7, 7, 6, 4, 4, 1, 0] (0x7f4166ac8780)
I think, it is because your function Sort (by the way it is better to rename it with lowercase sort()) it is changing the value of the original list. So, when you call with "ascending" or "descending", there's no problem becuse you only order one time, but with "both" the newList2 = Sort(inputList, "decending") use an a list mutated.
You never must work with the original list, always clone it and make the changes in the clone it. To work:
def Sort(inputs, order = "ascending"):
cloned_list = inputs[:]
if order == "ascending":
for i in range(len(cloned_list)):
for j in range(i + 1, len(cloned_list)):
if cloned_list[i] > cloned_list[j]:
cloned_list[i], cloned_list[j] = cloned_list[j], cloned_list[i]
elif order == "decending":
for i in range(len(cloned_list)):
for j in range(i + 1, len(cloned_list)):
if cloned_list[i] < cloned_list[j]:
cloned_list[i], cloned_list[j] = cloned_list[j], cloned_list[i]
else:
raise ValueError(order)
return cloned_list
Output:
[1, 4, 7, 7, 0, 6, 4] # a
[0, 1, 4, 4, 6, 7, 7] # b
[7, 7, 6, 4, 4, 1, 0] # c
So I understand how to make the merge sort algorithm in Python 3, and this is my code below for implementing the function:
def x(arr):
for i in mergeSort(arr):
yield from i
def mergeSort(arr):
if len(arr) > 1:
middle = len(arr) // 2
left = arr[:middle]
right = arr[middle:]
mergeSort(left)
mergeSort(right)
a = 0
b = 0
c = 0
while a < len(left) and b < len(right):
if left[a] < right[b]:
arr[c] = left[a]
a += 1
else:
arr[c] = right[b]
b += 1
c += 1
while a < len(left):
arr[c] = left[a]
a += 1
c += 1
while b < len(right):
arr[c] = right[b]
b += 1
c += 1
for i in mergeSort([6,3,8,7,4,1,2,9,5,0]):
print(i)
The gist of it is that the function returns the array sorted at the end. However, I am trying to build a sorting visualiser, and to do so, I need to make this function yield the array whenever a change is made so you can see the bars switch - so I need to make it a generator, but all attempts I've made to do so haven't worked. How could I modify my code to make this function a generator?
Thanks.
First you will need to make sure that a deeply recursive execution can actually report about the state of the whole list. With your current set up that is not possible, since the recursive function only gets to see a small slice of the array.
So, in order to fix that situation, don't pass slices with the recursive call, but pass start/end indices instead, giving access to the same arr to all function execution contexts.
Then you can yield arr after each merge. The code that makes the recursive call should use yield from.
I adapted your code only to apply the above idea:
def mergeSort(arr):
# arr is a unique list that all levels in the recursion tree can access:
def mergeSortRec(start, end): # separate function that can take start/end indices
if end - start > 1:
middle = (start + end) // 2
yield from mergeSortRec(start, middle) # don't provide slice, but index range
yield from mergeSortRec(middle, end)
left = arr[start:middle]
right = arr[middle:end]
a = 0
b = 0
c = start
while a < len(left) and b < len(right):
if left[a] < right[b]:
arr[c] = left[a]
a += 1
else:
arr[c] = right[b]
b += 1
c += 1
while a < len(left):
arr[c] = left[a]
a += 1
c += 1
while b < len(right):
arr[c] = right[b]
b += 1
c += 1
yield arr
yield from mergeSortRec(0, len(arr)) # call inner function with start/end arguments
for i in mergeSort([6,3,8,7,4,1,2,9,5,0]):
print(i)
For the example list, the output is the following:
[3, 6, 8, 7, 4, 1, 2, 9, 5, 0]
[3, 6, 8, 4, 7, 1, 2, 9, 5, 0]
[3, 6, 4, 7, 8, 1, 2, 9, 5, 0]
[3, 4, 6, 7, 8, 1, 2, 9, 5, 0]
[3, 4, 6, 7, 8, 1, 2, 9, 5, 0]
[3, 4, 6, 7, 8, 1, 2, 9, 0, 5]
[3, 4, 6, 7, 8, 1, 2, 0, 5, 9]
[3, 4, 6, 7, 8, 0, 1, 2, 5, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
You could decide to yield also the start/end indices, so that the consumer of the iterator knows where exactly the algorithm was manipulating the list. So then change:
yield arr
to:
yield arr, start, end
With that change, the output becomes:
([3, 6, 8, 7, 4, 1, 2, 9, 5, 0], 0, 2)
([3, 6, 8, 4, 7, 1, 2, 9, 5, 0], 3, 5)
([3, 6, 4, 7, 8, 1, 2, 9, 5, 0], 2, 5)
([3, 4, 6, 7, 8, 1, 2, 9, 5, 0], 0, 5)
([3, 4, 6, 7, 8, 1, 2, 9, 5, 0], 5, 7)
([3, 4, 6, 7, 8, 1, 2, 9, 0, 5], 8, 10)
([3, 4, 6, 7, 8, 1, 2, 0, 5, 9], 7, 10)
([3, 4, 6, 7, 8, 0, 1, 2, 5, 9], 5, 10)
([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 0, 10)
Maybe something like this:
def x(arr):
for i in mergeSort(arr):
yield i
def mergeSort(arr):
if len(arr) > 1:
middle = len(arr) // 2
left = arr[:middle]
right = arr[middle:]
mergeSort(left)
mergeSort(right)
a = 0
b = 0
c = 0
while a < len(left) and b < len(right):
if left[a] < right[b]:
arr[c] = left[a]
a += 1
else:
arr[c] = right[b]
b += 1
c += 1
while a < len(left):
arr[c] = left[a]
a += 1
c += 1
while b < len(right):
arr[c] = right[b]
b += 1
c += 1
return arr
# Entry point
generator = x([6,3,8,7,4,1,2,9,5,0])
print(next(generator)) # prints 0
print(next(generator)) # prints 1
# print the remaining elements
for i in generator:
print(i)
Output:
0
1
2
3
4
5
6
7
8
9
Note that a shorter recursive implementation of merge sort you could use could be the following:
def merge_sort(mylist):
if len(mylist) < 2:
return mylist
less = []
equal = []
greater = []
n = int(len(mylist)/2)
pivot = mylist[n]
for x in mylist:
if x < pivot:
less.append(x)
elif x == pivot:
equal.append(x)
elif x > pivot:
greater.append(x)
return merge_sort(less) + equal + merge_sort(greater)
I'm trying some python and I got this:
I have a string S='3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2' and m=9.
I want to know how many substrings with with sum equals m there are.
So with S and m above i whould get 7 as a result as:
'3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2'
_'0,4,0,3,1,0,1,0'_____________
_'0,4,0,3,1,0,1'_______________
___'4,0,3,1,0,1,0'_____________
____'4,0,3,1,0,1'_______________
____________________'0,0,5,0,4'_
______________________'0,5,0,4'_
_______________________'5,0,4'_
Now, the code i came up with does something like that
def es1(S,m):
c = 0
M = 0
ls = StringToInt(S)
for x in ls:
i= ls.index(x)
for y in ls[i+1:]:
M = x + y
if M == m:
c += 1
M = 0
break
if M > m:
M = 0
break
else:
continue
return c
def StringToInt(ls):
s = [int(x) for x in ls.split(',')]
return s
Where StringToInt obv gives me a list of int to work with.
The thing I don't get is where my concept is wrong since es1 returns 3
You could use zip to progressively add numbers to a list of sums and count how many 9s you have at each pass:
S = '3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2'
m = 9
numbers = list(map(int,S.split(",")))
result = 0
sums = numbers
for i in range(len(numbers)):
result += sums.count(m)
sums = [a+b for a,b in zip(sums,numbers[i+1:]) ]
print(result)
For a more "functional programming" approach, you can use accumulate from itertools:
from itertools import accumulate
numbers = list(map(int,S.split(",")))
ranges = (numbers[i:] for i in range(len(numbers)))
sums = (accumulate(r) for r in ranges)
result = sum( list(s).count(m) for s in sums )
print(result)
To explain how this works, let's first look at the content of ranges, which are substrings from each position up to the end of the list:
[3, 0, 4, 0, 3, 1, 0, 1, 0, 1, 0, 0, 5, 0, 4, 2]
[0, 4, 0, 3, 1, 0, 1, 0, 1, 0, 0, 5, 0, 4, 2]
[4, 0, 3, 1, 0, 1, 0, 1, 0, 0, 5, 0, 4, 2]
[0, 3, 1, 0, 1, 0, 1, 0, 0, 5, 0, 4, 2]
[3, 1, 0, 1, 0, 1, 0, 0, 5, 0, 4, 2]
[1, 0, 1, 0, 1, 0, 0, 5, 0, 4, 2]
[0, 1, 0, 1, 0, 0, 5, 0, 4, 2]
[1, 0, 1, 0, 0, 5, 0, 4, 2]
[0, 1, 0, 0, 5, 0, 4, 2]
[1, 0, 0, 5, 0, 4, 2]
[0, 0, 5, 0, 4, 2]
[0, 5, 0, 4, 2]
[5, 0, 4, 2]
[0, 4, 2]
[4, 2]
[2]
When we make a cumulative sum of the rows (sums), we obtain the total of values starting at the position defined by the row number and for a length defined by the column number. e.g. line 5, column 3 represents the sum of 3 values starting at the fifth position:
[3, 3, 7, 7, 10, 11, 11, 12, 12, 13, 13, 13, 18, 18, 22, 24]
[0, 4, 4, 7, 8, 8, 9, 9, 10, 10, 10, 15, 15, 19, 21]
[4, 4, 7, 8, 8, 9, 9, 10, 10, 10, 15, 15, 19, 21]
[0, 3, 4, 4, 5, 5, 6, 6, 6, 11, 11, 15, 17]
[3, 4, 4, 5, 5, 6, 6, 6, 11, 11, 15, 17]
[1, 1, 2, 2, 3, 3, 3, 8, 8, 12, 14]
[0, 1, 1, 2, 2, 2, 7, 7, 11, 13]
[1, 1, 2, 2, 2, 7, 7, 11, 13]
[0, 1, 1, 1, 6, 6, 10, 12]
[1, 1, 1, 6, 6, 10, 12]
[0, 0, 5, 5, 9, 11]
[0, 5, 5, 9, 11]
[5, 5, 9, 11]
[0, 4, 6]
[4, 6]
[2]
In this triangular matrix each position corresponds to the sum of one of the possible substrings. We simply need to count the number of 9s in there to get the result.
The above solutions will perform in O(N^2) time but, if you are concerned with performance, there is a way to obtain the result in O(N) time using a dictionary. Rather than build the whole sub arrays in the above logic, you could simply count the number of positions that add up to each sum. Then, for the sum at each position, go directly to a previous sum total that is exactly m less to get the number of substrings for that position.
from itertools import accumulate
from collections import Counter
numbers = map(int,S.split(","))
result = 0
sums = Counter([0])
for s in accumulate(numbers):
result += sums[s-m]
sums[s] += 1
print(result)
Note that all these solutions support negative numbers in the list as well as a negative or zero target.
As mentioned by others, your code only looks at sums of pairs of elements from the list. You need to look at sublists.
Here is a O(n) complexity solution (i.e. it's efficient since it only scans though the list once):
def es2(s, m):
s = string_to_int(s)
c = 0
# index of left of sub-list
left = 0
# index of right of sub-list
right = 0
# running total of sublist sum
current_sum = 0
while True:
# if the sub-list has the correct sum
if current_sum == m:
# add as many zeros on the end as works
temp_current_sum = current_sum
for temp_right in range(right, len(s) + 1):
if temp_current_sum == m:
c += 1
if temp_right<len(s):
temp_current_sum += s[temp_right]
else:
break
if current_sum >= m:
# move the left end along and update running total
current_sum -= s[left]
left += 1
else:
# move the right end along and update running total
if right == len(s):
# if the end of the list is reached, exit
return c
current_sum += s[right]
right += 1
def string_to_int(ls):
s = [int(x) for x in ls.split(',')]
return s
if __name__ == '__main__':
print(es2('3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2', 9))
This is the code you are looking for man. i felt looking by position was better for this problem so I did it and it worked.
def es1(S,m):
c = 0
M = 0
ls = StringToInt(S)
for i in range(0, len(ls)):
M = 0
for x in range(i, len(ls)):
M += ls[x]
if M == m:
c += 1
elif M >= m:
break
return c
def StringToInt(ls):
s = [int(x) for x in ls.split(',')]
return s
print(es1("3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2", 9))
OUTPUT:
7
Your code counts how many pairs of numbers there are in the String S which together give m while you actually want to test all possible substrings.
You could do something like:
numbers = [3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2]
m = 9
c = 0
for i in range(len(numbers)):
for j in range(len(numbers)-i):
sum = 0
for k in numbers[i:i+j]:
sum += k
if sum == m:
c += 1
print(c)
Output:
7
EDIT! ->This Code is actually all possible subsets, not sublists. I am going to leave this here though in case this solution is helpful to anyone who visits this question.
This code gets every solution. If you take a look in the function es1() the result variable is huge list of arrays with all the possible solutions.
import itertools
def es1(S,m):
result = [seq for i in range(len(StringToInt(S)), 0, -1) for seq in itertools.combinations(StringToInt(S), i) if sum(seq) == m]
return len(result)
def StringToInt(ls):
s = [int(x) for x in ls.split(',')]
return s
print(es1("3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2", 9))
OUTPUT:
4608
There are 4608 possible sets that add to the value 9.
s = "3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2"
m = 9
sn = s.replace(",","+") # replace "," with "+"
d = {} # create a dictionary
# create list of strings:
# s2 = ["3+0","0+4","4+0".............]
# s3 = ["3+0+4","0+4+0","4+0+3".............]
# .
# .
# .
for n in range(2,len(s.split(","))):
d["s%s"%n] = [sn[i:i+(2*n-1)] for i in range(0,len(sn),2)][:-n+1]
# evaluate whether sum of individual lists equal to m or not, then find out how many such lists are there
l = sum([eval(x)==m for y in d.values() for x in y] )
# remember we didnot add s1, i,e check whether individual string == m or not
l = l+sum([x==m for x in s.split(",")])
print(l)
7