JL Peyret
JL Peyret

Reputation: 12174

concatenate strings in list if separated by 0s

Basically, whenever two strings in a list are separated by one or more zeroes, I want to join them together. ['a',0,'b'] => ["ab"].

I've tried yield and I really can't find a good way to say if you find a zero in the list, concatenate the next non-zero to the previous string.

I've used yield before, but I am just not approaching this correctly. Mind you, I don't insist on using yield, it just seemed the most likely approach to work, since a simple list comprehension won't do it.

Sample data and expected outputs:

dataexp = [
    #input                          #expected
    (["a"],                         ["a"]),
    ([0,0,"a","b",],                ["a","b"]),
    ([0,"a","0",],                  ["a","0"]),
    (["a",0,"b",],                  ["ab"]),
    (["a",0,0,"b",],                ["ab"]),
    (["a","b",0],                   ["a","b"]),
    (["a","b","c"],                 ["a","b","c"]),
    (["a",0,"b",0, "c"],            ["abc"]),
    ]

Some sample code

I just don't handle the concatenate logic correctly and only filter5 is a serious attempt.

dataexp = [
    #input                          #expected
    ([0,0,"a","b",],                ["a","b"]),
    ([0,"a","0",],                  ["a","0"]),
    (["a",0,"b",],                  ["ab"]),
    (["a",0,0,"b",],                ["ab"]),
    (["a","b",0],                   ["a","b"]),
    (["a","b","c"],                 ["a","b","c"]),
    (["a",0,"b",0, "c"],            ["abc"]),
    ]

def filter0(li):
    return [val for val in li if isinstance(val, str)]


def filter3(li):
    pos = -1 
    len_li = len(li)
    while pos < len_li-1:
        pos += 1
        if li[pos] == 0:
            continue
        else:
            res = li[pos]
            yield res

def filter5(li):

    len_li = len(li)
    pos = 2
    p0 = p1 = None

    while pos < len_li-1:
        cur = li[pos]

        if p0 in (0, None):
            p0 = cur
            pos +=1 
            continue

        if cur == 0:
            p1 = cur
            pos += 1
            continue

        elif p1 == 0:
            p0 = p0 + cur
            pos += 1
            continue

        else:
            p1 = cur
            pos += 1
            yield p0

    if p0:
        yield p0
    if p1:
        yield p1


for fn in [filter0, filter3, filter5]:

    name = fn.__name__
    print(f"\n\n{name}:")

    for inp, exp in dataexp:
        try:
            got = list(fn(inp))
        except (Exception,) as e:
            got = str(e)

        msg = "%-20.20s for %-80.80s \nexp :%s:\ngot :%-80.80s:" % (name, inp, exp, got)
        if exp == got:
            print(f"\n✅{msg}")
        else:
            print(f"\n❌{msg}")

I am generating html dynamically by pushing strings into a big List[str] then "\n".join() it. Most of the time, that's fine, browsers ignore whitespace, but Cypress does care about the \n in <td>xyz\n</td>. So, rather than changing everything, I thought I'd find a way to suppress the newline by using mylist.extend(0, "</td>"). But now I am just curious at the look-behind/ahead nature of this list problem. And, if you think Django or Jinja Templates are better suited, you'd be correct, except that this is generating Django Templates, rather than the final html.

Upvotes: 1

Views: 120

Answers (1)

modesitt
modesitt

Reputation: 7210

I see no benefit of using a generator here. You can just keep track of the state determining your concat condition and either append or concatenate:

from typing import List, Literal, List

def process_list(l: List[Union[str, Literal[0]]]) -> List[str]:
    result, concat = [], False
    for e in l:
        if e == 0:
            concat = True
            continue
        if concat and result:
            result[-1] += e
        else:
            result.append(e)
        concat = False
    return result

Upvotes: 2

Related Questions