7

I'm trying to write a function count(s, chars) that takes a string s and a list of characters chars. The function should count the number of occurrences of the letters given in chars. It should return a dictionary where the keys are the characters given in the list of characters chars.

So for example:

In [1]: s = "Another test string with x and y but no capital h." In [2]: count(s, ['A', 'a', 'z']) Out[2]: 'A': 1, 'a': 3, 'z': 0 

I made some code that can count all the characters of the string and return a dictionary of it:

return {i: s.count(i) for i in set(s)} 

but I'm not sure how you would use a list of specific characters and return a dictionary...

4
  • {i: s.count(i) for i in l} where l is the list of characters or {i: c[i] for i in l} where c = collections.Counter(s). Commented Jan 15, 2017 at 18:09
  • @JimFasarakis-Hilliard: perhaps one should use c.get(i,0) instead of c[i] since it is possible the character did not occur in the string. Commented Jan 15, 2017 at 18:16
  • 1
    Counters return 0 on missing items already @WillemVanOnsem, no need to use get here :-) Commented Jan 15, 2017 at 18:17
  • 1
    @JimFasarakis-Hilliard: ah, ok I mised that. +1. Commented Jan 15, 2017 at 18:18

6 Answers 6

6

What about:

def count_chars(s,chars): return {c : s.count(c) for c in chars} 

Generates:

$ python3 Python 3.5.2 (default, Nov 17 2016, 17:05:23) [GCC 5.4.0 20160609] on linux Type "help", "copyright", "credits" or "license" for more information. >>> s = "Another test string with x and y but no capital h." >>> def count_chars(s,chars): ... return {c : s.count(c) for c in chars} ... >>> count_chars(s, ['A', 'a', 'z']) {'z': 0, 'A': 1, 'a': 3} 

Although this is rather inefficient. Probably a more efficiency way is do the counting in one step. You can use a Counter for this and then retain the interesting characters:

from collections import Counter def count_chars(s,chars): counter = Counter(s) return {c : counter.get(c,0) for c in chars} 
Sign up to request clarification or add additional context in comments.

3 Comments

well Counter is not as fast as str.count (see also Why is Collections.counter so slow?). You need to look for a lot of different characters with Counter to only come close to the str.count performance.
@MSeifert: but the point is that you will only need to loop once through the string. If you are interested in say 100 characters, you would have to use str.count 100 times, which will probably be slower than looping through it once using a Counter.
Well if you read the answer carefully, you will see I already claim this is not a good way to solve the problem and propose to use a counter. The first answer was more to show the OP a way to alter their implementation. Nevertheless the funny part is that MSeifert claims the opposite, so one of you is wrong :). I think it depends both on the length of the string and the number of characters one aims to count.
3
str.count(sub[, start[, end]]) 

Return the number of non-overlapping occurrences of substring sub in the range [start, end]. Optional arguments start and end are interpreted as in slice notation.

e.g. usage

>>> sentence = 'Mary had a little lamb' >>> sentence.count('a') 4 

so count function can be easily used here in this scenario as well. Below is the sample code snippet of the function

li=['A', 'a', 'z'] s = "Another test string with x and y but no capital h." def count(s, li): cnt=dict.fromkeys(li, 0) for c in li: cnt[c] = s.count(c) return cnt 

Console output will be like

>>> count(s, li) {'a': 3, 'A': 1, 'z': 0} 

Comments

2

You can do it 'old style' by using the dict fromkeys method to set all keys zeros and then increment for each character:

li=['A', 'a', 'z'] s = "Another test string with x and y but no capital h." def count(s, li): cnt={}.fromkeys(li, 0) for c in s: if c in cnt: cnt[c]=cnt[c]+1 return cnt >>> count(s, li) {'A': 1, 'a': 3, 'z': 0} 

Or, prefilter so you only test for keys that you are interested in:

def count(s, li): cnt={}.fromkeys(li, 0) for c in (e for e in s if e in cnt): cnt[c]+=1 return cnt 

But the fastest, most Pythonic is to use a Counter:

>>> from collections import Counter >>> c=Counter(s) >>> c Counter({' ': 10, 't': 7, 'n': 4, 'h': 3, 'i': 3, 'a': 3, 'o': 2, 'e': 2, 'r': 2, 's': 2, 'A': 1, 'g': 1, 'w': 1, 'x': 1, 'd': 1, 'y': 1, 'b': 1, 'u': 1, 'c': 1, 'p': 1, 'l': 1, '.': 1}) 

Then construct your desired dict from that:

>>> {k:c[k] for k in li} {'A': 1, 'a': 3, 'z': 0} 

Comments

1
 def count(s, chars): ret = dict(zip(chars, [0 for c in chars])) for c in s: if ret.has_key(c): ret[c] += 1 return ret 

Something like that maybe.

Comments

1

You can also build a dictionary with zip built-in method:

>>> s 'Another test string with x and y but no capital h.' >>> c ['A', 'a', 'z'] >>> def count_char(s, c): counts = map(s.count, c) return dict(zip(c, counts)) >>> >>> count_char(s, c) {'z': 0, 'A': 1, 'a': 3} 

Comments

1

Well, so many answers, I will throw in mine too, which is based on built in constructs:

from collections import Counter s = "Another test string with x and y but no capital h." chars = ['A', 'a', 'z'] count = Counter(s) # creates a dictionary count = {k:v for k, v in count.items() if k in chars} # take only charatcters from chars count.update({k:0 for k in set(chars) - set(s)}) # add zero instances print(count) === {'a': 3, 'A': 1, 'z': 0} 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.