3

I am trying to return a boolean which only gives the longest "True" occurrence in the original boolean and replace shorter "True" chunks into "False". Example a=[True, True, False, True , True, True, False], i want to return [False, False, False, True, True, True, False].

i tried more_itertools and it seems to have some interesting functions but not sure how to exactly implement for my purpose.

a=[True, True, False, True , True, True, False]

pred = lambda x: x in {True}

p=list(mit.run_length.encode(a))

>>>
Results in: (True,2),(False,1),(True,3),(False,1)

So what i want to eventually automatically get is (False,3),(True,3),(False,1). any suggestions? Thank you for your help

U13-Forward
  • 69,221
  • 14
  • 89
  • 114
Jamal
  • 45
  • 9
  • 1
    Where is the function `mit.run_length.encode` defined? Also could you explain your output – Devesh Kumar Singh May 25 '19 at 05:25
  • @ Devesh Kumar Singh the link is here:https://more-itertools.readthedocs.io/en/latest/index.html i guess it is in version 4. I had to install it. – Jamal May 25 '19 at 05:36

2 Answers2

3

Below solution should work after using more_itertools.run_length.

Essentially, the logic is to find the length of longest subsequence of True, and the location of that index in result list
then count the total elements before and after that longest subsequence, then construct the resultant list of tuples accordingly.

import more_itertools as mit

a=[True, True, False, True , True, True, False]

result = list(mit.run_length.encode(a))

#Find the length of longest subsequence of True, and the location if that index in result
max_true_count = -1
max_true_idx  = -1
for idx, (val, count) in enumerate(result):
    if val and max_true_count < count:
        max_true_count = count
        max_true_idx = idx

#Find total elements before and after the longest subsequence tuple
elems_before_idx = sum((idx[1] for idx in result[:max_true_idx]))
elems_after_idx = sum((idx[1] for idx in result[max_true_idx+1:]))

#Create the output list using the information
output = [(False, elems_before_idx), (True, max_true_count), (False, elems_after_idx)]
print(output)

The output will be

[(False, 3), (True, 3), (False, 1)]
Devesh Kumar Singh
  • 20,259
  • 5
  • 21
  • 40
  • Im trying this a=[(False, 22), (True, 62), (False, 10), (True, 4), (False, 102)], but the result is weirdly [(False, 94), (True, 4), (False, 102)]. Can you kindly verify this?? – Jamal May 25 '19 at 08:30
2

Here's a vectorized one -

def keep_longest_true(a):
    # Convert to array
    a = np.asarray(a)

    # Attach sentients on either sides w.r.t True
    b = np.r_[False,a,False]

    # Get indices of group shifts
    s = np.flatnonzero(b[:-1]!=b[1:])

    # Get group lengths and hence the max index group
    m = (s[1::2]-s[::2]).argmax()

    # Initialize array and assign only the largest True island as True.
    out = np.zeros_like(a)
    out[s[2*m]:s[2*m+1]] = 1
    return out

def island_info(a):
    '''' Get island tuple info
    '''

    # Attach sentients on either sides w.r.t array start and end
    b = np.r_[~a[0],a,~a[-1]]

    # Get group lengths and group start elements
    lens = np.diff(np.flatnonzero(b[:-1] != b[1:]))
    grpID = np.resize([a[0],~a[0]],len(lens))

    # zip those two info for final o/p
    return zip(grpID,lens)

Sample run -

In [221]: a
Out[221]: [True, True, False, True, True, True, False]

In [222]: keep_longest_true(a)
Out[222]: array([False, False, False,  True,  True,  True, False])

In [223]: island_info(keep_longest_true(a))
Out[223]: [(False, 3), (True, 3), (False, 1)]
Divakar
  • 218,885
  • 19
  • 262
  • 358