(Dictionary) storing keys with x,y in Python - python

What I am trying to do is to store an x,y value with a key. For example, in my case, I need it so that once any x,y has reached the value of 3, some process happens.
Here is what I have tried: However, this gives me an error, as I am unable to store lists within dictionaries.
dictionary= {}
player = [0,0]
def Checking():
if player in dictionary:
dictionary[[player]] +=1
print("repopulate", dictionary)
else:
dictionary[player] = 0
print(dictionary)
if dictionary.get(player) >= 3:
print("It is done!")
EDIT:
Sorry about the lack of clarity in the question. The player variable is the user input of where the user wishes to move within the x,y given. There are multiple treasures, and if the user is to chose a position x,y which is the same as a treasure x,y; then +1 should be added to that treasure. Once a treasure reaches 3, it should be diminished.

I think you want to use player as your key, and the count as the value of that key:
>>> treasure_hits = {}
>>> player = (0,0)
>>> try:
... treasure_hits[player] += 1
... except KeyError:
... treasure_hits[player] = 0
...
>>> treasure_hits
{(0, 0): 0}
>>>
>>> try:
... treasure_hits[player] += 1
... except KeyError:
... treasure_hits[player] = 0
...
>>> treasure_hits
{(0, 0): 1}
>>>
Making treasure_hits a tuple instead of a list allows it to be used as a key since it is immutable

If you save you list x,y in the dictionary like this, that also depends on your condition when you want to change the values you have to iterate through the list.
treasureHits = {}
player = [0,0]
def myFunction():
treasureHits["key"]=[p+1 for p in player]
print treasureHits["key"]
myFunction()
That's what I understand from your question.

So the easiest way to do this is to call str() on the player variable. This will turn the list into a string. You need to do this because dictionaries cannot use lists as keys. So try the following: treasureHits[str(player)]
Note thought that this is usually not recommended because you will have very unusual keys and if anyone else will be editing your code it could be confusing. Make sure to leave plenty of comments in your code!

Related

Looping through attributes within Class instances?

I am trying to simulate a baseball game to learn more about python and programming in general... I ran into an interesting learning point in programing... and was wondering if someone could explain this error...
import random
rosterHome = []
rosterAway = []
class Player:
def __init__(self, number, battingAverage):
self.number = number
self.battingAverage = battingAverage
class Game:
def __init__(self):
self.inning = 0
self.homeScore = 0
self.awayScore = 0
self.outs = 0
def createStats():
for i in range(40):
stats = random.random()
x = Player(i, stats)
rosterHome.append(x)
for y in range(40):
stats = random.random()
y = Player(i, stats)
rosterAway.append(y)
def startGame():
Game.createStats()
Game.inning = 0
Game.homeScore = 0
Game.awayScore = 0
Game.outs = 0
Game.playInning()
def playInning():
totalHits = 0
if Game.inning >= 10:
print('Game is Over')
return
while Game.outs < 3:
for i in rosterHome:
x = rosterHome[i]
if x.battingAverage > random.random():
totalHits += 1
player += 1
print('batter ', player, ' got a hit')
else:
Game.outs += 1
player += 1
print('batter ', player, ' got out')
print('there are ', Game.outs, ' outs.')
Game.startGame()
x = rosterHome[i]
TypeError: list indices must be integers or slices, not Player
TLDR:
List indices must be integers or slices
The interpreter says "Hey, I see you're trying to access an item in a List by its index, but indices should be of type integer, however, you passed a value of type Player"
In Python and most programming languages, to reference an item in a List/Array, one way would be by index. Lists are zero-indexed, so the first item is of index 0, the second index 1, and so on.
Given an Array
my_array = ["bread", "foo", "bar"]
my_array[0] # would give you "bread"
my_array[1] # would give you "foo"
my_array[2] # would give you "bar"
However in your case, if we trace back up from where the error occurred, right here:
x = rosterHome[i]
You want to ask, what is the value of i? above this line is a for loop, and i represents each value in a list called rosterHome. So what the heck is in rosterHome anyways?
Moving up into your createStats method where you populated the rosterHome list, we see that you're pushing an instance of Player into the rosterHome list.
x = Player(i, stats)
rosterHome.append(x)
So rosterHome really isn't a list of numbers but instead a list of Player instances. You might want to review and try again, maybe accessing the number property of the Player object instead.
The error happens because rosterHome is a list of instances of the Player class, so when you iterate on the list (for i in rosterHome) each element will be an instance of said class (i is a Player). If you want to access the number of each player you'll have to access the attribute number of your Player instances, but it seems like actually you want to find the player instance. This means, you don't even need to lookup the value in the table, just use the value of the for loop. I'll use a different naming of variables to improve readability:
while Game.outs < 3:
for player in rosterHome:
# x wanted to access a player, but we don't need to do that actually
if player.battingAverage > random.random():
# ...
else:
# ...
This part of the answer considers that you actually want to meet both requirements (number of outs and iterate players once):
player_index = 0
while Game.outs < 3 and player_index< len(rosterHome):
player = rosterHome[player_index]
if player.battingAverage > random.random():
# ...
else:
# ...
if Game.outs == 3:
# Reached 3 outs
else:
# No players left and game outs < 3

Function to check if dictionary value is occupied

I'm trying to make a function to check whether a value added to a dictionary already exists.
If a value is already in the dictionary, it should print "Occupied" and not add the value to the existing key.
I have tried to get it to not append when the new input is similar, but it still adds the new input even though it is the same as the previous.
For example, if I add input_v as "Hi" --> XO = {'key': ["Hi"]}
If I were to put in "Hi" again, I then want it to say "Occupied", but as of right now it still adds to the dictionary.
XO = {'key': []}
def check_values(input_v):
value = input_v
print(XO)
if value in XO.values():
print("Occupied")
else:
XO['key'].append(value)
The issue is in the way you referenced the value of the 'key'. Use this:
XO = {'key': []}
def check_values(input_v):
value = input_v
global XO
#print(XO)
if value in XO['key']:
print("Occupied")
else:
XO['key'].append(value)
#print(XO)
d = dict()
for c in a:
if c not in d:
d[c] = 1
else:
print("Occupied")
Would this work? a is a list in this example.

How do I call a function from a sorted dictionary for every time the parent function is called?

(So I have a group of levels for a game, lets just say level1 - level10.
I have a function called level_up() and inside I have a dictionary that is used to group "level name" as a key to be stored in a json file and used later, and a value that is the function to be called.
So what this looks like is:
levels = {
"level1":level1 #level1 is the function to be executed
"level2":level2
}
all the way down to the tenth level.
I would try to call the function like so:
a = list(sorted(levels.keys())) # to sort the keys in order
b=level.values()
list(sorted(b))
b = b.pop(0)
b()
This of course results in an error
TypeError: '<' not supported between instances of 'function' and 'function'
I guess it would be easier to just make two lists but for learning purposes would like to see if I could make this function nice and concise so feel free to give any advice.
Why use strings as keys? Simpler, no need to sort:
import sys
def level1(): print(1)
def level2(): print(2)
def level3(): print(3)
def win():
print("you won")
sys.exit()
curr_lvl = 1 # start here and advance
levels = { 1:level1, 2:level2, 3:level3}
while True:
levels.get(curr_lvl,win)() # get func and call it
curr_lvl += 1
Output:
1
2
3
you won
If you really nead a "string" key - process it:
def get_level(s):
levels = { 1:level1, 2:level2, 3:level3, 4:level4, 5:level5}
try:
lvl = int(s.lstrip("level"))
except ValueError:
pass
return levels.get(lvl,win)
get_level("level2")() # prints 2
There is no such thing as a "sorted dictionary". Let that be clear.
Here is a possible answer, I am sure there is a more beautiful way:
map(lambda i: i[1], sorted(levels.items(), key=lambda i: i[0]))

Need a way to store type of data

I'm making a battleship game for a practice exercise. I want the player to be able to type in two coordinates, and if those coordinates are a hit, it should return that. If those coordinates are the hit on a ship that sinks it, it should say so. I tried doing a dictionary that contains a list of lists, but I don't know how to search the values to see if the coordinates are inside it. I tried doing my_dict.values() to access the coordinates, but since the information is stored inside another list it won't find it. Here is some example code so this might make more sense.
my_dict = {"hats":[[2,3],[4,5]], "shoes":[[6,7], [8,9]]}
print my_dict.values()
if [2,3] in my_dict.values():
print "Success!"
else:
print "Failure"
You can just iterate through the values and check if the position is in the current value.
For example:
my_dict = {"hats":[[2,3],[4,5]], "shoes":[[6,7], [8,9]]}
print my_dict.values()
for value in my_dict.values():
if [2,3] in value:
print "Success!"
else:
print "Failure"
You could also do this with any.
my_dict = {"hats":[[2,3],[4,5]], "shoes":[[6,7], [8,9]]}
print my_dict.values()
if any([2, 3] in value for value in my_dict.values()):
print "Success!"
else:
print "Failure"

What is the best way to append lists inside a dict?

I am trying to build a list that has 1 key to many values. The best way I can think to do this is by pointing a key value to a list. However, I am having trouble building the lists inside the dict.
num_items = len(decoded_data['data']['arrivalsAndDepartures'])
buses = list()
busdict = dict()
val = list()
for i in range(num_items):
decoded_data['data']['arrivalsAndDepartures']
bus = decoded_data['data']['arrivalsAndDepartures'][i]['routeId']
buses.append(bus)
try:
busdict[bus]
except KeyError:
busdict[bus] = [i]
print("except "+ bus , str(i))
else:
val = busdict[bus]
busdict[bus] = [val].append(i)
print("else "+ bus ,val, str(i))
This gives me weird results.
$ python test.py
except 40_590 0
except 40_554 1
except 40_592 2
else 40_590 [0] 3
except 1_122 4
except 40_577 5
else 40_590 None 6
From the above test result, the third time it hits the key '40_590' the value is cleared.
busdict[bus] = [val].append(i)
list.append is an inplace operation and returns None. So, you are clearing the previously stored list in it. You could fix it like this
busdict[bus].append(i)
But the best way to solve this problem is by using dict.setdefault function (which assigns and returns the default value if the specified key is not found), like this
busdict.setdefault(bus, []).append(i)
But the best way to solve this problem would be to use collections.defaultdict, like this
from collections import defaultdict
busdict = defaultdict(list)
...
...
busdict[bus].append(i)
list.append() does not return a value. Use it like this:
else:
val = busdict[bus].append(i)
print("else "+ bus ,val, str(i))
By the way: use four spaces for indents!

Categories