I have a large dictionary in which I am scanning an API and adding values to based on if the shots taken in a hockey game are goals or not. Here is my code right now...
for key in contents['liveData']['plays']['allPlays']:
# for plays in key['result']['event']:
# print(key)
if (key['result']['event'] == "Shot"):
#print(key['result']['event'])
scoordinates = (key['coordinates']['x'], key['coordinates']['y'])
if scoordinates not in shots:
shots[scoordinates] = (1, 0)
else:
shots[scoordinates] += (1, 0)
if (key['result']['event'] == "Goal"):
#print(key['result']['event'])
gcoordinates = (key['coordinates']['x'], key['coordinates']['y'])
if gcoordinates not in shots:
shots[gcoordinates] = (1, 1)
else:
shots[gcoordinates] += (1, 1)
I was trying to add two values to the dict by using parentheses, but this doesn't work because whenever there is a duplicate coordinate shot the table will add the value like this (1,0, 1, 1) instead of doing (2,1). Is this possible? I was thinking there might be a simple formatting fix here, but I am not totally sure.
You can use sum instead of +=:
a = tuple(map(sum, zip(a, b)))
So for this situation use:
shots[gcoordinates] = tuple(map(sum, zip((1, 1), shots[gcoordinates])))
Use the following function to sum tuples:
import operator
def sum_tuples(tuple_1, tuple_2):
return tuple(map(operator.add, tuple_1, tuple_2))
Related
Im trying to create a function that records the amount of times a value in a list is repeated in a row. After about an hour of deliberation, I was able to reach a stable-looking conclusion, yet i am unable to receive the desired outcome
lst = [1,2,2,2,3,1,1]
def compress(numlist):
intervals,x=0,0
for i in numlist:
if i == numlist[x]:
intervals+=1
elif i != numlist[x]:
print((intervals,numlist[x]), end=" ")
x+=intervals
intervals=1
compress(lst)
Here, I was trying to get the function to "compress" the list of integers
When I run the code, the outcome is:
(1, 1) (3, 2) (1, 3)
While the desired outcome is:
(1, 1) (3, 2) (1, 3) (2,1)
You only show a run when you find a value that is not equal to the previous one. There is no value after the last value, of course, so the last run is never printed. Just add a line after the loop to print the last run.
if intervals != 0:
print((intervals,numlist[x]))
By the way, you don't need the elif conditional. All you need there is an else, since if i == numlist[x], then the only other thing possible is i != numlist[x].
I would like to generate pairs of integers forever sorted by the sum of their absolute values from smallest to biggest. However I don't want to return any that have a 0 for either part of the pair. So I would like:
(1, 1)
(-1, -1)
(1, 2)
(-1, -2)
(2, 1)
(-2, -1)
[...]
I saw Iterate over pairs in order of sum of absolute values which has really great answers such as:
def pairSums(s = 0): # base generation on target sum to get pairs in order
while True: # s parameter allows starting from a given sum
for i in range(s//2+1): # partitions
yield from {(i,s-i),(s-i,i),(i-s,-i),(-i,i-s)} # no duplicates
s += 1
I could filter out the pairs with a 0 in them but that seems ugly and inefficient (most of the pairs seem to have a 0 in them). Is there way to generate them directly?
I think you just need to exclude the cases i=0 and i=s?
def pairSums(s = 0): # base generation on target sum to get pairs in order
while True: # s parameter allows starting from a given sum
for i in range(1, s//2+1): # partitions
if i != s:
yield from {(i,s-i),(s-i,i),(i-s,-i),(-i,i-s)}
s += 1
As part of a dynamical programming assignment, I find myself having to do the following.
I have two sorted lists of length 2 tuples (ordered pairs, representing scores on two criteria). One pair of values can only be considered strictly greater than another if it is greater on one criterion and not lower on the other. So, (1,8) and (2,7) are incomparable, while (1,7) is lower than (2,8).
Each input list contains only values that are incomparable with each other. My method merges the two lists, omitting duplicates as well as any values that are strictly inferior to another value in the new, bigger list. Then it sorts the new list.
For example, the following input produces this result:
combine([(1,8), (2, 6), (3, 4)], [(2, 7), (3, 3)])
[(1, 8), (2, 7), (3, 4)]
Here's the code I have currently produced:
def combine(left, right):
# start with lists sorted from biggest to smallest
newlist = left+right
leftlen = len(left)
for i in range(leftlen - 1, -1, -1):
l = newlist[i] # candidate value to be inserted in
for j in range(len(newlist) - 1, leftlen - 1, -1):
r = newlist[j]
if r[0] >= l[0]: # cell with >= food encountered without having previously encountered cell with less water
if r[1] >= l[1]: # this cell also has more water - del candidate
del newlist[i]
leftlen -=1
elif r[0] == l[0]: # equal food and less water than candidate - candidate wins
del newlist[j]
break # either way, no need to consider further cells -
# if this cell doesn't beat candidate, then candidate belongs
if r[1] <= l[1]: # cell with less water encountered before cell with more food
del newlist[j]
for k in range(j -1, leftlen - 1, -1): # continue through right list, deleting cells until a value with
# higher food is found
r = newlist[k]
if r[0] > l[0]: break
else: del newlist[k]
break
newlist.sort(reverse=True)
return newlist
This code does work, but I am wondering if there is a faster approach to solving this kind of problem? When the lists are long, I end up making a lot of pairwise comparisons.
I've tried to prune out some unnecessary comparisons, relying upon the fact that items in each list are always greater on one criterion and lesser on the other. Thus, the lists are reverse sorted on the first value in the tuple, and therefore also sorted on the second value!
One idea I had was to try and use a different ADT - some type of tree perhaps, but I'm not sure if this is going to help or not.
Any suggestions? This is for an assignment, so I'm looking for ideas rather than for somebody to rewrite the whole thing for me :) Cheers!
Essentially what I'm trying to do is write the enumerate function recursively. I'm fully aware that doing this recursively is not optimal and that there is already a built-in enumerate function in python.
def enumeration(mylist, idx=0):
if idx == 0:
return [(idx, mylist[idx]), enumeration(mylist, idx+1)]
elif idx != len(mylist)-1:
return (idx, mylist[idx]), enumeration(mylist, idx+1)
else:
return idx, mylist[idx]
Now it's not the enumeration part that's difficult. It's getting the tuples to match up where they should be. If mylist was set to ["The", "tree", "then"], the output would be "[(0, "the"), ((1, "tree"), (2, "then"))] when I want it to look like [(0, "the"), (1, "tree"), (2, "then")].
I know what is causing the problem but I have no idea how to fix it. I've tried using '+' instead of ',' in the return statements but that just leads to [(0, "the", 1, "tree", 2, "then")] which I also don't want.
The problem is that the return type of your enumeration is not consistent:
if the index is 0 it returns a list[pair, enumeration()]
if the index is neither 0 nor end-of-list, it returns a Pair[Pair, enumeration]
if the index is end-of-list, it returns a simple pair
You need your various cases to be consistently typed in such a way that you can "recombine" your items. Since enumeration() should return a sequence, logically each recursive case needs to return a list (of pairs).
Then you need to do a recursive case analysis. Generally, recursion consists of two items:
how do you decide to end the recursion and what do you do in that case
what do you do in the normal case
Here the terminal case is pretty simple: if you're past the end of the list, just return an empty list. Incidentally this is something you're not handling at all: try calling enumerate([]) and see what happens.
Then the normal recursive case: just generate a pair of (index, item), call enumerate() with an incremented index, and concatenate the two.
def enumerate(mylist, idx=0):
# note: terminal case is really `idx == len(mylist)`, you may want to generate an error if `idx > len(mylist)` instead as that's an incorrect use of the API
if idx >= len(mylist):
return []
else:
return [(idx, mylist[idx])] + enumerate(mylist, idx+1)
Other than the behaviour with empty lists, your version also uses idx completely differently: in the original enumerate it's just the index that's returned, it's not used to manipulate the input (indeed the input is not necessarily indexable). So e.g. enumerate(range(3), 5) would yield (5, 0), (6, 1), (7, 2). Your version would either error out or end, because it would try to access the 5th item of a range(3).
this will work
def enumeration(mylist, idx=0):
if idx == 0:
return [(idx, mylist[idx])]+(enumeration(mylist, idx+1))
elif idx < len(mylist)-1:
return [(idx, mylist[idx])]+(enumeration(mylist, idx+1))
else:
return [(idx, mylist[idx])]
output:
mylist=["asd","gsd","fff","adf"]
enumeration(mylist, idx=0)
[(0, 'asd'), (1, 'gsd'), (2, 'fff'), (3, 'adf')]
First of use a list to hold the values.
Second instead of calling the next recursion with a , use + to add to the list of values , this way each tuple gets added to the same list.
This is my first question here so I accept any/all tips in case my question is not properly worded.
First off, the problem:
Say we have the following array A = [(1,'cat'), (1,'dog'), (0,'giraffe'), (0,'cheetah'),(1,'elephant')]
I need to use an algorithm that will sort this list based on the first element of each component (meaning the number). It is specifically mentioned that it does not have to be a stable algorithm (I guess meaning that we do not need to consider the sorting of the words after the number, just the 0s being before all the 1s)
I should also mention that I do not wish to employ the strategies of creating side-arrays that I will populate with the results as the algorithm sorts them. The requirement is for the algorithm to sort the array within the same array.
The code I have devised is the following:
def SwapAround(A, start, end):
start_pos = start
for i in range(start,end):
if A[i] < A[end]:
A[i], A[start_pos] = A[start_pos], A[i]
start_pos = start_pos + 1
A[start_pos], A[end] = A[end], A[start_pos]
return start_pos
A=[(1,'cat'),(0,'dog'),(1,'kangaroo'),(0,'mule'),(1,'giraffe'),(1,'dog'),
(0,'bat')]
SwapAround(A,0,len(A) - 1)
print(A)
I am having rather peculiar issues with it, although I am pretty confident that it should be working (at least walking down the code line by line it made good sense to me).
The code sorts the list, but not completely... for example, my most recent output was:
[(0, 'bat'), (0, 'dog'), (1, 'kangaroo'), (0, 'mule'), (1, 'giraffe'), (1, 'dog'), (1, 'cat')]
With a smaller list, it has actually worked, and I was dumbfounded to wake up this morning to add a couple more components to my list and it not working.
Could you possibly tell me if you can see something readily "wrong" that I should consider, and the rationale behind that so that I may fully comprehend it.
Second Question: If I wanted to add components to my list that had the number 2 as well (meaning my algorithm would have to sort between 0,1,2 instead of just 0 and 1) would you use a completely different algorithm or should swapping still work? My initial thought was that Swapping would not work properly (and it hasn't with this algorithm) and maybe a CountingSort or RadixSort would work better, so your input would be very much appreciated.
Your algorithm is conceptually wrong, though it's already close to the solution.
The important problem with your algorithm is that only the first element to swap will ever change. Instead you need to move both the index of the last and first element.
def sort_binary_key(arr):
l, u = 0, len(arr) - 1
while l < u:
if arr[l] == 1 and arr[u] == 0:
arr[l], arr[u] = arr[u], arr[l]
elif arr[l] == 1:
u -= 1
elif arr[u] == 0:
l += 1
else:
u -= 1
l += 1
For the second part of the question:
Yes, it's possible. Run the above algorithm twice. In the first run, move all elements with 0 to the lower part of the array, all other elements to the upper. Afterwards run the same algorithm over the second part of the array, sorting between elements with 1 and 2 as first tuple-member.
def sort_binary_key(arr, l, u, key_mapper):
while l < u:
al, au = key_mapper(arr[l]), key_mapper(arr[u])
if al == 1 and au == 0:
arr[l], arr[u] = arr[u], arr[l]
elif al == 1:
u -= 1
elif au == 0:
l += 1
else:
u -= 1
l += 1
return l
def sort_ternary(arr):
tmp = sort_binary_key(arr, 0, len(arr) - 1, lambda t: 0 if t == 0 else 1)
sort_binary_key(arr, tmp, len(arr) - 1, lambda t: 0 if t == 1 else 1)
Note that the above code is only intended as a demonstration. This code works with lists of integers instead of the input provided by OP.
Your algorithm could not work from a much deeper level.
You running an O(n) complexity general sorting algorithm. There is no algorithm for general sorting with that average complexity (if you find one, let me know!). Check this table of complexities of different sorting algorithms.
If your scenario is only with 0 and 1, and you want all the 0 at the start and 1 at the end (unstable), then it could be done with O(n)
(Check Paul's Answer to see how) and your algorithm is utterly different.
You can use python list sort and just pass the key:
A = [(1,'cat'), (1,'dog'), (0,'giraffe'), (0,'cheetah'),(1,'elephant')]
sorted(A, key=lambda x: x[0])
>>> [(0, 'giraffe'), (0, 'cheetah'), (1, 'cat'), (1, 'dog'), (1, 'elephant')]
You can also make it consider secondary key (first name and secondly a number):
B = [(1,'cat'), (0,'cat'), (0,'giraffe'), (0,'cheetah'),(1,'elephant')]
sorted(B, key=lambda x: (x[1], x[0]))
>>> [(0, 'cat'), (1, 'cat'), (0, 'cheetah'), (1, 'elephant'), (0, 'giraffe')]
Python has a default sorting and in your case, you could simply write:
C = [(1,'cat'), (0,'cat'), (0,'giraffe'), (0,'cheetah'),(1,'elephant')]
sorted(C)
>>> [(0, 'cat'), (1, 'cat'), (0, 'cheetah'), (1, 'elephant'), (0, 'giraffe')]