1


I have recently been creating a guessing game for my co - workers as a project to learning Python 3.3x. I have been storing the results in a text file formatted with the name and score, separated by a colon, as shown...

Adam:12
Dave:25
Jack:13
Adam:34
Dave:23

The text file is read with the following code, thanks to Padraic Cunningham.

from collections import defaultdict
d = defaultdict(list)
with open('guesses.txt') as f:
    for line in f:
        name,val = line.split(":")
        d[name].append(int(val))

for k in sorted(d):
    print(k," ".join(map(str,d[k])))

The issue now is, is that I want to see Dave, Adam and Jack's most recent four scores. One way that I thought about this is to somehow read the list above and reverse it, so that it would see the most recent results first. I thought I could first inverse the dictionary, using the line of code below:

inv_map = {v: k for k, v in d.items()}

But that does not work, as it returns the error:

TypeError: unhashable type: 'list'

As I want to store the 4 most recent results, then I would need to make sure that the oldest result is deleted every time a new result arrives, and updates the dictionary.

How would I be able to make sure that only 4 maximum values are assigned to each key? Could that be done by inversing the dictionary? I have tried to see if other questions follow the same principle, but I have not found anything as such.

NOTE I have seen the itemgetter method, but I have MORE than one value for each key.

The text file would appear like this:

Adam:12
Dave:25
Jack:13
Adam:34
Dave:23
Jack:17
Adam:28
Adam:23
Dave:23
Jack:11
Adam:39
Dave:44
Jack:78
Dave:38
Jack:4    
Delbert J. Nava
  • 121
  • 1
  • 9
  • 1
    possible duplicate of [A user score saving program](http://stackoverflow.com/questions/28326725/a-user-score-saving-program) – Reut Sharabani Feb 08 '15 at 08:14
  • 1
    As you can see in the duplicate, you can serialize to files real python objects (in your case that will be a dictionary of string->list) , which should make this **a lot** easier. – Reut Sharabani Feb 08 '15 at 08:14

1 Answers1

2

You COULD use a defaultdict with deque(maxlen=4) to handle that.

import collections

d = collections.defaultdict(lambda: collections.deque(maxlen=4))
# defaultdict accepts as an argument a function that returns the default
#   state of the value of undefined keys. In this case we make an anonymous
#   function that returns a `collections.deque` with maxlen of 4.

# we could also do
# # import functools, collections
# # d = collections.defaultdict(functools.partial(collections.deque,
# #                                               maxlen=4))

with open('path/to/file.txt', 'r') as infile:
    for line in infile:
        player,score = line.strip().split(":")
        d[player].append(int(score))

However you're probably better off just creating this data structure to begin with and pickling the object.

import pickle

# `highscores` is some previously populated high score dict

def save_scores(filename):
    with open(filename, 'w') as outfile:
        pickle.dump(highscores, outfile)

def load_scores(filename):
    with open(filename, 'r') as infile:
        highscores = pickle.load(infile)
    return highscores
Adam Smith
  • 52,157
  • 12
  • 73
  • 112
  • Oh ok. But, when I use my `print(dict(d))` method, it prints out this: – Delbert J. Nava Feb 08 '15 at 08:25
  • `{'Jack': deque([17, 11, 78, 4], maxlen=4), 'Dave': deque([23, 23, 44, 38], maxlen=4), 'Adam': deque([34, 28, 23, 39], maxlen=4)}` – Delbert J. Nava Feb 08 '15 at 08:25
  • How do I get rid of the deque and the maxlen elements to reveal the dictionary itself? or even better, how could I then print it neatly, so it only reads `Jack 17 11 78 4` without the brackets? @adamsmith – Delbert J. Nava Feb 08 '15 at 08:26
  • That dictionary has one value per key, that value is a `deque` object (which itself has a `maxlen` attribute). You can print it nicely by doing something like [this](https://gist.github.com/NotTheEconomist/c0b688f5e1d2f4bd0978) – Adam Smith Feb 08 '15 at 08:31
  • Yes, that works. But then when I sorted the keys in alphabetical order, all the names came up in the order Adam, Dave and Jack using the `for k in sorted(d)` line. How can I still keep its functionality of having it print it out in alphabetical order? – Delbert J. Nava Feb 08 '15 at 08:37
  • @DelbertJ.Nava `sorted(d)` gives you a list of the keys in `d` in alphabetical order. You could sort `d.items()` and give it a `key` kwarg so `sorted` knows how to handle the resulting object, e.g. `sorted(d.items(), key=lambda kv: kv[0])` or you could do `for k in sorted(d):` and assign the `values` in the first line `for k in sorted(d): values = d[k]; ...` – Adam Smith Feb 08 '15 at 08:40
  • Sounds like you've messed up your indents :-D look through it again. Debug debug debug. – Adam Smith Feb 08 '15 at 08:48
  • OH GUESS WHAT! it worked, apart from my one error of absolute stupidity. Thanks! But oh wait, it doesn't read it in order of most recent... I'll try that myself now. Thanks anyway! – Delbert J. Nava Feb 08 '15 at 09:01
  • @DelbertJ.Nava it should populate in order of the file. The last 4 entries in the file for each key are saved in the `deque` – Adam Smith Feb 09 '15 at 01:38