1

I have a headache and dictionary like this:

{a: ['+','+','-','-','+','-','-','+'],
b: ['+','+','+','-','-','+','+','+','-'],
c: ['-','-','-','+','+','+']}

And I want to know how many times the string of values change, something like this:

a = 4
b = 3
c = 1

I have tried using groupby from itertools, by doing this:

for k, v in mydict.iteritems():
    print k + ' ' + str([len(list(g[1])) for g in groupby(list(v)) if g[0] =='+'])

But I get only a list containing two values (two string switches).. I have tried changing the '+' and '-' characters without success, any recommendations?

adrtam
  • 6,991
  • 2
  • 12
  • 27
fcalles
  • 35
  • 4
  • You can code your own loop akin to https://stackoverflow.com/a/2936861/1317713 Instead of remembering the sign, remember the last value. – Leonid Mar 19 '19 at 15:51

2 Answers2

4

Something you could do is build a dictionary using a dictionary comprehension and count how many times the values in each entry in the dictionary change:

d = {'a': ['+','+','-','-','+','-','-','+'], 'b': ['+','+','+','-','-','+','+','+','-'], 
     'c': ['-','-','-','+','+','+']}

s = {k : sum(1 for i,j in zip(d[k][1:], d[k][:-1]) if i != j) for k in d}
# {'a': 4, 'b': 3, 'c': 1}

Or if you prefer itertools.groupby:

{k : sum(1 for i in groupby(d[k]))-1 for k in d}
# {'a': 4, 'b': 3, 'c': 1}

Details

In order to detect a change in the elements in each list, you can compare its elements with a lagged version of the list, which can be done by zipping two slices of the list, zip(d[k][1:], d[k][:-1]).

For instance, for key a:

list(zip(d['a'][1:], d['a'][:-1]))
# [('+', '+'), ('-', '+'), ('-', '-'), ('+', '-'), ('-', '+'), ('-', '-'), ('+', '-')]

Now simply use a generator expression and add 1 each time the values in a tuple are different:

sum(1 for i,j in zip(d['a'][1:], d['a'][:-1]) if i != j)
# 4
yatu
  • 86,083
  • 12
  • 84
  • 139
  • As a note to OP, the `d[k][1:], d[k][:-1]` offsets the two lists by one so you can do an element-wise comparison rather than storing the last value and checking – C.Nivs Mar 19 '19 at 15:53
  • amazing yatu, thank you, have upvoted but I get some message about new user`s votes are not visualized or something like that. – fcalles Mar 20 '19 at 08:56
  • @fcalles you can also upvote now with your rep :-) (thanks for accepting!) – yatu Mar 20 '19 at 15:14
2

You don't need to filter. Just count the groupby:

mydict = {'a': ['+','+','-','-','+','-','-','+'],
'b': ['+','+','+','-','-','+','+','+','-'],
'c': ['-','-','-','+','+','+']}

for k,v in mydict.items():
  print(k + ' ' + str(len(list(itertools.groupby(list(v))))-1))
adrtam
  • 6,991
  • 2
  • 12
  • 27