Python - Get more values by key instead of one - python-3.x

I'm currently trying to cache much stuff on my web game.
Its kinda a speedrun game, where you have specific sections and it saves each duration for a section in a dict.
So right now, i have a pretty long dict:
dict = [{'account_id': '10', 'Damage': 4874, 'duration': 50.020756483078},
{'account_id': '10', 'Damage': 5920, 'duration': 20.020756483078},
{'account_id': '10', 'Damage': 2585, 'duration': 30.02078},
{'account_id': '4', 'Damage': 3145, 'duration': 21.020756483078},
{'account_id': '4', 'Damage': 4202, 'duration': 60.020756483078},
{'account_id': '4', 'Damage': 5252, 'duration': 66.020756483078}]
(Its much more, up to 10 sections for an account_id, but I just created an example to use for this question)
Then we need to assign those times to an account_id
enterDict = {}
for x in dict :
enterDict[x["account_id"]] = x
But when I try to get the times from the cache, via
account_id = "4"
EnterInfo = enterDict[account_id]
print(EnterInfo)
It only returns one
{'Damage': 5252, 'account_id': '4', 'duration': 66.020756483078}
As an addition:
If we resolve this, is there a way I can give them an order? Since dicts are messing up everything.
So it should start from the lowest duration to the top one, since thats the right correct order.
So I could just use [0] for the lowest duration of 21 [1] for 60 and [2] for 66. I wouldnt mind if there is a new key : value with "order": "0", "order": "1" and "order":"2"
{'account_id': '4', 'Damage': 3145, 'duration': 21.020756483078},
{'account_id': '4', 'Damage': 4202, 'duration': 60.020756483078},
{'account_id': '4', 'Damage': 5252, 'duration': 66.020756483078}]

What you actually want to do is to create a list of dictionaries as a value behind your 'account_id' key. Now you're replacing with each addition the previous value for the key instead of adding (appending) to it.
See 1 for a example how to initialize lists within a dictionary.
See 2 for a example to order a lists of dicts on a certain value. However I could also suggest a Pandas Dataframe for this Job.
This could be a solution:
from collections import defaultdict
from operator import itemgetter
enterDict = defaultdict(list)
for item in dict:
enterDict[item['account_id']].append(item)
sortDict = defaultdict(list)
for key_of_dict in enterDict:
sorted_list = sorted(enterDict[key_of_dict], key=itemgetter('duration'))
sortDict[key_of_dict] = sorted_list

Related

How to iterate a list, to get combination of all next values

Problem: Obtain the combination of all next values of the array.
Explanation: All the values should be formed by contiguous elements in the array.
Posible solution(not optimal):
l_number= list("24256")
result= []
while l_number:
n = ""
for x in l_number:
n += x
result.append(str(n))
l_number.pop(0)
print(result)
The output:
['2', '24', '242', '2425', '24256', '4', '42', '425', '4256', '2', '25', '256', '5', '56', '6']
I got this, but it is not very efficient.
Is there any optimized way to do this?
Since you will be outputting all contiguous sublists, the size of the output will be O(N^2) where N is the length of the list, and time complexity will be at least quadratic no matter what (You could achieve linear space complexity by using a generator). Here is one way to compute all contiguous substrings with a list comprehension:
s = "24256"
n = len(s)
res = [s[i:j] for i in range(n) for j in range(i+1,n+1)]
print(res)
# ['2', '24', '242', '2425', '24256', '4', '42', '425', '4256', '2', '25', '256', '5', '56', '6']
As an aside, it is usually undesirable to build up lists with str += ... since a new copy of str is created on each iteration. One workaround is to create a list of components and call .join once all components have been found.

Why list remains unchanged Python

After iterating through a list to change each value to an integer, the list remains unchanged with all the values still being strings.
As a result, sorting does not get applied either
a = ['14', '22', '4', '52', '54', '59']
for ea in a:
ea = int(ea)
a.sort()
print (a)
Output: '14', '22', '4', '52', '54', '59'
Should be : 4, 14, 22, 52, 54, 59
Your code is not changing the list itself. You are creating a new variable, converting it to an int, and throwing it away.
Use this instead
a = ['14', '22', '4', '52', '54', '59']
a = list(map(int, a)) #this converts the strings into integers and assigns the new list to a
a.sort() #this sorts it
print (a)
ea = int(ea) is not changing the element within the list. So as you do not change the list (which can be seen if you print the list before sorting it), the sort operation is doing it's job correctly because it is sorting strings here, not integer values.
You could change your loop to provide the index and modify the original entries in the list by using the enumerate function as follows:
a = ['14', '22', '4', '52', '54', '59']
for index, ea in enumerate(a):
a[index] = int(ea)
a.sort()
print(a)

How to determine "event" output to print on the outcome of a random dice roll?

I'm trying to have certain strings print out depending on which dice roll is made.
I have tried making lists for what rolls get which event, but even at that no event prints out only what i have rolled.
import random
def dice_roll():
d20_roll = random.randint(1,20)
print("You rolled " +str(d20_roll))
def dice_choice():
event = str(d20_roll)
bad_list = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10',
'11', '12']
good_list = ['13', '14', '15', '16', '17', '18']
gag_list = ['19', '20']
if event == bad_list:
print('bad_list stuff')
elif event == good_list:
print('good_list stuff')
else:
if event == print gag_list:
print("gag_list stuff")
dice_choice()
dice_roll()
I expect the output to be any of the three options the random roll will make.
What I receive is just the result of the dice_roll itself, without the choice.
First, check your indentation, your call to dice_choice() seems to be inside dice_choice() itself, second, there is a syntax error in your test if event == print gag_list:, third, you are testing whether a string equals a list, instead you should test whether the string is in the list, your code should be like this:
import random
def dice_roll():
d20_roll = random.randint(1,20)
print("You rolled " +str(d20_roll))
def dice_choice():
event = str(d20_roll)
bad_list = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']
good_list = ['13', '14', '15', '16', '17', '18']
gag_list = ['19', '20']
if event in bad_list: # check using `in` not `===`
print('bad_list stuff')
elif event in good_list:
print('good_list stuff')
elif event == gag_list:
print("gag_list stuff")
dice_choice()
dice_roll()
Example Output:
You rolled 11
bad_list stuff

finding non matching records in pandas

I would like to identify if a set of records is not represented by a distinct list of values; so in this example of:
raw_data = {
'subject_id': ['1', '2', '3', '4', '5'],
'first_name': ['Alex', 'Amy', 'Allen', 'Alice', 'Ayoung'],
'last_name': ['Anderson', 'Ackerman', 'Ali', 'Aoni', 'Atiches'],
'sport' : ['soccer','soccer','soccer','soccer','soccer']}
df_a = pd.DataFrame(raw_data, columns = ['subject_id', 'first_name', 'last_name','sport'])
raw_data = {
'subject_id': ['9', '5', '6', '7', '8'],
'first_name': ['Billy', 'Brian', 'Bran', 'Bryce', 'Betty'],
'last_name': ['Bonder', 'Black', 'Balwner', 'Brice', 'Btisan'],
'sport' : ['soccer','soccer','soccer','soccer','soccer']}
df_b = pd.DataFrame(raw_data, columns = ['subject_id', 'first_name', 'last_name','sport'])
raw_data = {
'subject_id': ['9', '5', '6', '7'],
'first_name': ['Billy', 'Brian', 'Bran', 'Bryce'],
'last_name': ['Bonder', 'Black', 'Balwner', 'Brice'],
'sport' : ['football','football','football','football']}
df_c = pd.DataFrame(raw_data, columns = ['subject_id', 'first_name', 'last_name','sport'])
raw_data = {
'subject_id': ['1', '3', '5'],
'first_name': ['Alex', 'Allen', 'Ayoung'],
'last_name': ['Anderson', 'Ali', 'Atiches'],
'sport' : ['football','football','football']}
df_d = pd.DataFrame(raw_data, columns = ['subject_id', 'first_name', 'last_name','sport'])
frames = [df_a,df_b,df_c,df_d]
frame = pd.concat(frames)
frame = frame.sort_values(by='subject_id')
raw_data = {
'sport':['soccer','football','softball']
}
sportlist = pd.DataFrame(raw_data,columns=['sport'])
Desired output: I would like to get a list of first_name and last_name pairs that do not play football. And also I would like be able to return a list of all the records since softball is not represented in the original list.
I tried using merge with how= outer, indicator=True options but since there is a record that plays soccer there is a match. And the '_right_only' yields no records since it was not populated in the original data.
Thanks,
aem
If you only want to get the names of people who do not play football all you need to do is:
frame[frame.sport != 'football']
Which would select only those persons who are not playing football.
If it has to be a list you can further call to_records(index=False)
frame[frame.sport != 'football'][['first_name', 'last_name']].to_records(index=False)
which returns a list of tuples:
[('Alex', 'Anderson'), ('Amy', 'Ackerman'), ('Allen', 'Ali'),
('Alice', 'Aoni'), ('Brian', 'Black'), ('Ayoung', 'Atiches'),
('Bran', 'Balwner'), ('Bryce', 'Brice'), ('Betty', 'Btisan'),
('Billy', 'Bonder')]
You can also use .loc indexer in pandas
frame.loc[frame['sport'].ne('football'), ['first_name','last_name']].values.tolist()
[['Alex', 'Anderson'],
['Amy', 'Ackerman'],
['Allen', 'Ali'],
['Alice', 'Aoni'],
['Brian', 'Black'],
['Ayoung', 'Atiches'],
['Bran', 'Balwner'],
['Bryce', 'Brice'],
['Betty', 'Btisan'],
['Billy', 'Bonder']]

Predicted Rank Values from Dict

Lets say I have a time dict
dict = {
'9': {'auth': '9', 'duration': 154.92},
'10': {'auth': '10', 'duration': 132.72},
'4': {'auth': '4', 'duration': 144.59}
}
and how can I get the "rank" value from the dict with a new duration number, lets say 133.92.
It should return dict index 1, since the top list is:
auth-10|duration:132.72
auth-4|duration:144.59
auth-9|duration:154.92
and 133.92 is bigger than 132.72, but less than 144.59 or 154.92
I'm sorry if Its unclear explained, but I tried my best.
EDIT:
I'm trying it again:
I need a function which returns the "predicted/rank" for a custom duration from the sorted list/sorted by "duration/DESC".
So a duration of 160 would return the last place, which is 4. (index+1). A 120 duration should return me the first position which is index 0 or 1st (index+1).
As #MartijnPieters mentioned, dictionaries lack indices, but they do have keys. The following function pred() (short for "predecessor") returns the key of the item whose duration is the largest duration <= the passed duration. It returns None (which can be tested for) if the passed duration is smaller than all of the durations in the dictionary:
from bisect import bisect_left
def pred(duration, entries):
entries = list(entries.items())
entries.sort(key = lambda x: x[1]['duration'])
durations = [x[1]['duration'] for x in entries]
j = bisect_left(durations,duration)
if j == 0:
return None
else:
return entries[j-1][0]
For example, if
d = {
'9': {'auth': '9', 'duration': 154.92},
'10': {'auth': '10', 'duration': 132.72},
'4': {'auth': '4', 'duration': 144.59}
}
(by the way -- don't use dict as an identifier since it has a predefined meaning in Python) then:
>>> pred(133.92,d)
'10'
>>> pred(149.92,d)
'4'
>>> pred(159.92,d)
'9'
>>> pred(129.92,d)
>>>
Note that
>>> pred(129.92,d) == None
True
On Edit: Here is another variation on the same idea, one that returns an integer rank:
def rank(duration, entries):
entries = list(entries.items())
durations = sorted(x[1]['duration'] for x in entries)
return bisect_left(durations,duration)
Then:
>>> rank(133.92,d)
1
>>> rank(129.92,d)
0
Final Edit: At the cost of some readability, here is a 1-liner:
def rank(duration, entries):
return bisect_left(sorted(v['duration'] for v in entries.values()),duration)

Resources