1

I have created Counter objects containing characters and the number of times those characters occur in a given file. I would like to be able to display these data sets in a more readable and useful format, such as CSV.

Here's a sample Counter object:

Counter({u' ': 10304, u'0': 1630, u'\n': 1516, u'*': 1196, u'.': 1026, u'1': 1003, u'A': 991, u'E': 954, u'9': 937, u'S': 845, u'R': 834, u'T': 781, u'O': 745, u'2': 736, u'F': 726, u'4': 653, u'N': 596, u'C': 575, u'3': 558, u'L': 557, u'5': 535, u'I': 532, u'8': 481, u'7': 456, u'6': 410, u'P': 400, u'\t': 388, u'G': 377, u'M': 327, u'Y': 326, u'D': 323, u'e': 305, u'B': 292, u'U': 272, u'H': 256, u'a': 224, u'r': 216, u'W': 208, u'l': 178, u'/': 174, u'K': 167, u'i': 164, u'V': 160, u'o': 155, u't': 155, u'X': 153, u'b': 134, u'-': 132, u'n': 130, u's': 112, u'$': 97, u'@': 96, u':': 89, u'g': 85, u'c': 84, u'Q': 75, u'v': 75, u'u': 71, u'd': 69, u'+': 68, u'#': 63, u'y': 59, u'h': 58, u'm': 52, u'p': 42, u'Z': 36, u'f': 32, u')': 26, u'(': 26, u'w': 22, u'%': 21, u',': 21, u'!': 17, u'=': 16, u'k': 13, u'J': 12, u'&': 10, u'x': 7, u"'": 6, u'q': 6, u'z': 2})

It is similar to a dictionary, but I can't figure out how to properly extract the key, value pairs, let alone write them to a CSV file. The following code creates a CSV file and writes the counts to the characters column while not writing the characters to the file at all. This is as far as I have gotten.

with open('{}.csv'.format(str(counter_object)), 'w') as csvfile:
    fieldnames = ['character', 'count']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)

    writer.writeheader()
    for dictionary in counter_object:
        for character, count in dictionary.items():
            writer.writerow(dict(character=count))

Is there any protocol for dealing specifically with Counter objects in such a way?

EDIT

I saw this post here, but trying that solution results in an error:

    for key, count in <counter_object>.items():
AttributeError: 'tuple' object has no attribute 'items'
muad-dweeb
  • 995
  • 1
  • 9
  • 24

2 Answers2

0

The issue is the way you create your dict, try something like this instead:

writer.writerow({'character':character,'count':count})
#or
writer.writerow(dict(character=character,count=count))

The reason your existing code causes a problem is evident if you run the following code, you'll see something like this:

>>> print(dict(character=count))
{'character': 4 }

You're creating a dict with a single Key value pair with the key as 'character' and the value as the count.

EDIT:

You also have an issue with your loop, rather than two nested for loops, you can try this:

for character, count in counter_object.items():
Harry Harrison
  • 591
  • 4
  • 12
  • This is giving me: `AttributeError: 'unicode' object has no attribute 'items'` – muad-dweeb Nov 17 '15 at 00:06
  • `for character, count in counter_object: ValueError: too many values to unpack` – muad-dweeb Nov 17 '15 at 00:09
  • My counter_object is being recognized as a tuple by Python, and as such has no items attribute. – muad-dweeb Nov 17 '15 at 00:11
  • In which case your code is now different from the example you posted - and I can't help any more without seeing up-to-date code – Harry Harrison Nov 17 '15 at 00:12
  • No you're right, for some reason my counter object is starting out wrapped in a tuple, so I'm using a for loop to extract it first. Unfortunately, my first comment still stands: `'unicode' object has no attribute 'items'` The counter object looks exactly the same as it does in the original post, but it isn't functioning like a dictionary. – muad-dweeb Nov 17 '15 at 20:28
  • @SCK - the issue you have now, is that you're using a for loop to act on BOTH parts of the tuple, but the Counter object is only 1 of the two parts I expect the other part is a string, use something like `(s, counter) = counter_object` to split the tuple - assuming the counter object is the second item in the tuple – Harry Harrison Nov 17 '15 at 20:44
  • Right again. I hacked this ugly script together as I was trying to figure out Counter objects and in the mess I was generating them inside of an unwanted tuple. A colleague just pointed out the tuple generation to me. In the end, the problem was my own crappy code, but your suggested for loop was the way to go for extracting the key/value pairs. – muad-dweeb Nov 17 '15 at 20:56
0

A DictWriter expects you to pass it each row as a dictionary object where the keys are the same as the fieldnames you constructed it with. You could either do that:

writer.writerows({'character': k, 'count': v} for k, v in counter_object.items())

or simply use a regular writer instead of a dictwriter and just pass it items() directly:

writer = csv.writer(csvfile)
writer.writerow(fieldnames)   # write header explicitly
writer.writerows(counter_object.items())  # no transformation needed

Note that you don't need for loops in either case, you can just use a list comprehension in combination with the writerows() method.

tzaman
  • 46,925
  • 11
  • 90
  • 115
  • This is giving me: `AttributeError: 'tuple' object has no attribute 'items'` – muad-dweeb Nov 17 '15 at 00:07
  • Do I first need to manually get rid of the `Counter(...)` wrapper around the dictionary for any of this to work? – muad-dweeb Nov 17 '15 at 00:08
  • Nope, a `Counter` is still a dictionary, so it should work fine. Where are you getting a `tuple` from? You should remove any `for` loops if you still have them.. – tzaman Nov 17 '15 at 00:09