Home > Blockchain >  Incrementally adding 1 to two different values per key in a dictionary
Incrementally adding 1 to two different values per key in a dictionary

Time:10-28

EDIT: Added example code at the bottom

I'm using dictionaries to keep track of two values for a given key. As an example, I want to keep track of how many balls and strikes a couple baseball players get. So I have two baseball players:

  1. Tim
  2. Mark

All of there stats are listed in a text file like:

  • Tim gets a strike
  • Tim gets a ball
  • Tim gets a strike
  • Mark gets a ball

And so on and so forth. So for the first line, the dictionary would like this (reflecting Tim getting a strike).

stats = {'tim', [1, 0]}

Then he gets a ball:

stats = {'tim', [1, 1]}

Then another strike:

stats = {'tim', [2, 1]}

Then Mark gets a ball:

stat = {'tim', [2, 1],
       'mark', [0, 1]}

Started tackling this by creating two dictionaries (one for strikes, one for balls), but I ran into two problems:

  1. When I attempted to append value from strikes to balls for one player I ran into the error:

    TypeError: 'int' object is not iterable

I'm assuming this means append() doesn't work for integers, but I'm not sure. I also tried using str() to change the value, but ran into the same error.

  1. Even if I could solve this problem, I need to put in 0's when a strike or ball is not recorded.

Here's the general code I have at the moment:

#!/usr/bin/env python3

import re

strike = {}
ball = {}

with open("baseball_stats.txt", "r") as file:
    for line in file:
        player = re.search(r"^\s*([a-zA-Z] )", line)
        name = player.group(1)
        if "strike" in line:
            if name in strike:
                strike[name]  = 1
            else:
                strike[name] = 1
        else:
            if name in ball:
                ball[name]  = 1
            else:
                ball[name] = 1

## This is where I tried to combine the tow into the Strike dictionary and add 0's when no strikes where recorded

for key, value in ball.items():
   if key in strike.keys():
       addBall = ball[key]
       strike[key].append(addBall)
   else:
       strike[key] = 0
       addBall = ball[key]
       strike[key].append(addBall)

Basically, I think I'm going about this all wrong and figured I ask for guidance. Let me know if I need to elaborate on anything. Anything helps!

CodePudding user response:

If you plan on keeping more stats per player later, a nested dictionary is probably best. The defaultdict class (from collections) will make this easy to use.

Input:

events = ["Jim ball",
          "Jim strike",
          "Jim strike",
          "Jim ball",
          "Jim strike out",
          "Tom ball",
          "Tom hit out",
          "Mark strike",
          "Mark ball",
          "Mark hit onBase" ]

Process:

from collections import defaultdict
players = defaultdict(lambda:defaultdict(int))
for event in events:
    player,*keywords = event.split()
    for stat in keywords:
        players[player][stat]  = 1

Output:

print(players)

defaultdict(<function <lambda> at 0x7fc0f9996400>, 
{'Jim': defaultdict(<class 'int'>, 
        {'ball': 2, 'strike': 3, 'out': 1}), 
 'Tom': defaultdict(<class 'int'>, 
        {'ball': 1, 'hit': 1, 'out': 1}), 
'Mark': defaultdict(<class 'int'>, 
        {'strike': 1, 'ball': 1, 'hit': 1, 'onBase': 1})
})

print(players['Jim']['ball']) # 2
print(sum(stats['strike'] for stats in players.values())) # 4 
print(max(players,key=lambda p:players[p]['ball'])) # Jim

CodePudding user response:

This is my simple solution to your problem (and yes, you should post your code so people can try to help!):

events = [["Tim", "strike"],
["Tim", "ball"],
["Tim" , "strike"],
["Mark", "ball"]]

res = {}
for e in events:
    player = res.get(e[0], [0, 0])
    if e[1] == "strike":
        player[0]  = 1
    elif e[1] == "ball":
        player[1]  = 1
    res[e[0]] = player

 print(res)
  • Related