2

Can someone explain this to me, and/or direct me on the right/pythonic way of doing this?

Python 2.7.

Ultimately, I am trying to loop through dictionary countsD:

countsD = {"aa": None, "bb": None, "cc": None, "dd": None} 

and for the match in a corresponding dictionary d:

d = {"aa": (5689, 34, 44, 77, 88, 321), "bb": (33, 6742, 89744), "cc": (45, 98), "dd": (1, 33)}

add the count of items as a value to the corresponding matching key, to create finally this countsD

{"aa": 6, "bb": 3, "cc": 2, "dd": 2}

If I do this with the above

> d = {"aa": (5689, 34, 44, 77, 88, 321), "bb": (33, 6742, 89744), "cc": (45, 98), "dd": (1, 33)}

> for key in d:

>>     print(key)
>>     print(len(d[key]))

Returned is this, which is what I want

aa
6
cc
2
dd
2
bb
3

HOWEVER, if one of the values for a key only contains 1 value (entirely possible), like (see "cc"):

d = {"aa": (5689, 34, 44, 77, 88, 321), "bb": (33, 6742, 89744), "cc": (45), "dd": (1, 33)}

and then run the same for loop, I get an error on the "cc" key:

aa
6
cc
Traceback (most recent call last):
  File "<interactive input>", line 3, in <module>
TypeError: object of type 'int' has no len()

HOWEVER again, if I make that "cc" key have an empty value (), then all is fine again.

d = {"aa": (5689, 34, 44, 77, 88, 321), "bb": (33, 6742, 89744), "cc": (), "dd": (1, 33)}

>>> d = {"aa": (5689, 34, 44, 77, 88, 321), "bb": (33, 6742, 89744), "cc": (), "dd": (1, 33)}
>>> for key in d:
...     print(key)
...     print(len(d[key]))
... 
aa
6
cc
0
dd
2
bb
3

And in typing the title for this post just now, I was referred to Count number of values in dictionary for each key for an answer. Great, one line! But again, for a key with just one value, it fails. This good:

>>> d = {"aa": (5689, 34, 44, 77, 88, 321), "bb": (33, 6742, 89744), "cc": (), "dd": (1, 33)}
>>> new_countsD = {k: len(v) for k,v in d.items()}
>>> new_countsD
{'aa': 6, 'bb': 3, 'cc': 0, 'dd': 2}

this not, see key "cc"

>>> d = {"aa": (5689, 34, 44, 77, 88, 321), "bb": (33, 6742, 89744), "cc": (111), "dd": (1, 33)}
>>> new_countsD = {k: len(v) for k,v in d.items()}
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
  File "<interactive input>", line 1, in <dictcomp>
TypeError: object of type 'int' has no len()

So, what gives?? I feel like I am missing something stupid...

Thanks for any help!

jpp
  • 159,742
  • 34
  • 281
  • 339
noydb
  • 59
  • 2
  • 8
  • 1
    Possible duplicate of [How to create a tuple with only one element](https://stackoverflow.com/questions/12876177/how-to-create-a-tuple-with-only-one-element) – jpp Jun 29 '18 at 22:34
  • True. Sometimes, especially when you're new to this, you just don't exactly know what to search for to figure it out yourslef. Ultimately, I did not know that what I was dealing here was a tuple. But, all these responses were helpful, good learning for me. – noydb Jun 30 '18 at 00:19

2 Answers2

4

In python, a single-item tuple (called a singleton) is written as (value,), so the (111) in your input should be written as (111,) instead; otherwise it would be considered an integer of 111.

From tuple's documentation:

A special problem is the construction of tuples containing 0 or 1 items: the syntax has some extra quirks to accommodate these. Empty tuples are constructed by an empty pair of parentheses; a tuple with one item is constructed by following a value with a comma (it is not sufficient to enclose a single value in parentheses). Ugly, but effective.

>>> empty = ()
>>> singleton = 'hello',    # <-- note trailing comma
>>> len(empty)
0
>>> len(singleton)
1
>>> singleton
('hello',)
blhsing
  • 91,368
  • 6
  • 71
  • 106
2

This is happening because when you save a value like cc with only one value, it is just saved as an int and is no longer a tuple, which means it does not have a len() function. You can just add a check of the value's type, such as:

if type(d[key]) == int:
    print(1)
else:
    print(len(d[key]))

This way, you will not try to access the length property of an int, and will not get your error.

  • Thank-you for the help!! But I must say that seems odd that you can't get a length of 1 for one item, but you can get a length/count of zero for no items.... in a tuple. I'm not a pro at this, so not for me to understand yet :-D – noydb Jun 29 '18 at 19:35
  • So how would you implement this test for int vs tuple with 'new_countsD = {k: len(v) for k,v in d.items()}' ??? – noydb Jun 29 '18 at 19:36