1

I have the following code and am attempting to iterate over the results of each line and check if a calculated value in the 'untrained' dictionary is greater than 50%. However, some of the lines are NoneType and I am getting error: TypeError: 'NoneType' oject is not subscriptable. Is there a way I can ovoid this and still iterate to get my desired output below?

from collections import namedtuple
from itertools import zip_longest

trained = {'Dog': 4, 'Cat': 3, 'Bird': 1, 'Fish': 12, 'Mouse': 19, 'Frog': 6}
untrained = {'Cat': 6, 'Mouse': 7, 'Dog': 3, 'Wolf': 9}

Score = namedtuple('Score', ('total', 'percent', 'name'))

trained_scores = []
for t in trained:
    trained_scores.append(
        Score(total=trained[t],
              percent=(trained[t]/(trained[t]+untrained.get(t, 0)))*100,
              name=t)
    )

untrained_scores = []
for t in untrained:
    untrained_scores.append(
        Score(total=untrained[t],
              percent=(untrained[t]/(untrained[t]+trained.get(t, 0)))*100,
              name=t)
    )

# trained_scores.sort(reverse=True)
# untrained_scores.sort(reverse=True)

row_template = '{:<30} {:<30}'
item_template = '{0.name:<10} {0.total:>3} ({0.percent:>6.2f}%)'
print('='*85)
print(row_template.format('Trained', 'Untrained'))
print('='*85)

for trained, untrained in zip_longest(trained_scores, untrained_scores):
    x = row_template.format(
        '' if trained is None else item_template.format(trained),
        '' if untrained is None else item_template.format(untrained)
    )
    print(x)

Current Output:

=====================================================================================
Trained                        Untrained                     
=====================================================================================
Mouse       19 ( 73.08%)       Mouse        7 ( 26.92%)      
Cat          3 ( 33.33%)       Cat          6 ( 66.67%)      
Frog         6 (100.00%)       Wolf         9 (100.00%)      
Dog          4 ( 57.14%)       Dog          3 ( 42.86%)      
Bird         1 (100.00%)                                     
Fish        12 (100.00%) 

Desired Output:

=====================================================================================
Trained                        Untrained                     
=====================================================================================
Mouse       19 ( 73.08%)       Mouse        7 ( 26.92%)       
Cat          3 ( 33.33%)       Cat          6 ( 66.67%)  <-- Above 50%    
Frog         6 (100.00%)       Wolf         9 (100.00%)  <-- Above 50%      
Dog          4 ( 57.14%)       Dog          3 ( 42.86%)      
Bird         1 (100.00%)                                     
Fish        12 (100.00%)                                     

Update!:

Updated with the suggested code that works. Thanks for all the help!

if untrained is not None and untrained[1] > 50:
    print(x + '<-- Above 50%')
else:
    print(x)

Result:

=====================================================================================
Trained                        Untrained                     
=====================================================================================
Mouse       19 ( 73.08%)       Wolf         9 (100.00%)       <-- Above 50%
Fish        12 (100.00%)       Mouse        7 ( 26.92%)      
Frog         6 (100.00%)       Cat          6 ( 66.67%)       <-- Above 50%
Dog          4 ( 57.14%)       Dog          3 ( 42.86%)      
Cat          3 ( 33.33%)                                     
Bird         1 (100.00%)        
3
  • What do you mean by total=trained[t]? When you make a loop for t in trained:, t already contains the element you need, not the index of the element. Commented Aug 14, 2016 at 13:44
  • 1
    @IgorPomaranskiy iterating over a dict returns its keys... so trained[t] will access its value... Commented Aug 14, 2016 at 13:45
  • @JonClements sorry, you are right, my bad! Commented Aug 14, 2016 at 13:47

2 Answers 2

4

Skip over None values

if untrained is None:
    continue
Sign up to request clarification or add additional context in comments.

3 Comments

Or in the more Pythonic version, if not untrained:
@DeepSpace I'd rather NOT recommend to use such approach. Sometimes it's reliable enogh, but sometimes it is not. if not untrained will skip not only on Nones, but also on 0s and empty data structures (lists, tuples, sets etc), which can be not desired and sometimes hard to find out why the results are not correct. So it's better to do explicit comparison: if untrained is not None:.
@Akilesh I added the suggested code but now I am missing some values from the first column (trained). I pasted the modified code above with its result. Can you please check what I am doing wrong?
2

You can not just skip the lines where untrained is None or you will skip the trained values, too. Instead, you should add an additional guard directly to the if condition checking whether the percentage is > 50:

if untrained is not None and untrained[1] > 50:
    print(x + '<-- Above 50%')
else:
    print(x)

2 Comments

That is EXACTLY it! Did not think to add the additional 'and' statement. I hope the universe rewards you and all that helped me today. Thank you very much!
Any tricks that would allow to fold it into a one short line? I have a hierarchical tree and I wrote custom iterator to skip nulls down stream pointers, but I still have to explicitly check that the current element is not null and spend one if statement and one indent every time I do it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.