• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1767
  • Last Modified:

Convert array to a dictionary of counts?

Is there a built-in function that converts an array of strings into a dictionary, where each key is a unique element in the array, and each value is the number of times that the corresponding key appeared in the array? I wrote such a function (below), but I would prefer to use either a built-in function, or at least a function from a common library.

def setToMap(array):
    dict = {}
    for element in array:
        if element in dict:
            dict[element] += 1
            dict[element] = 1
    return dict

2 Solutions
No, I don't believe there's a built-in function to do this.

Most people build up their own module of such functions, and import that module into each of their projects.
In fact, you are implementing the multi-set (or bag). Using the dictionary type, which is very efficient in Python, is fine for that. Even the Sets module--the predecessor of built-in set type--implemented the sets  using the dictionary type. The comment says "This module implements sets using dictionaries whose values are ignored."

I personally would call the function bagFromSeq(seq), because you can iterate through any sequence of whatever the same way. I would also not use the identifier dict for the dictionary, because you are masking the same name of a built-in type.

You can even think about building your class Bag(dict):  if it makes sense in your case. Otherwise, you code looks fine.
BerkeleyJeffAuthor Commented:
Thanks for the suggestions. In response, I've rewritten the code and moved it to a seperate module:

def accumulate(hash, key, value):
    if key in hash:
        hash[key] += value
        hash[key] = value

def multisetCounts( multiset ):
    counts = {}
    for element in multiset:
        accumulate(counts, element, 1)
    return counts

Is there anything further that could be improved? I'm pretty new to Python, coming from Perl. Btw/in Perl this type of routine could be written in one short line:

map {counts{$_}++} multiset;

I'm surprised Python (a successor to Perl, known for its elegance) would require 5x as much code.
Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

For what it's worth, here's how I'd spell it:

def count_items(seq):
    counts = {}
    for s in seq:
        counts[s] = counts.get(s, 0) + 1
    return counts

if __name__ == '__main__':
    TEST = ['red', 'green', 'blue', 'green', 'pink', 'red', 'green']
    print count_items(TEST)

And also for what it's worth, one of the reasons Python is more elegant than Perl is that you can't express four line's worth of code in one line.  8-)
ramromconsultant Commented:
map(lambda x:counts.update({x:counts.get(x,0)+1}),seq)
BerkeleyJeffAuthor Commented:
Thanks! It was the 'get' function that I was looking for.

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now