Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace patterns of a list of any type of object similar to .replace for strings

With a string you can replace substrings of length greater than 1. For example, 'abcabc'.replace('abca','*') yields '*bc'.

I would like to do this with a list. For example, something like this:

[1, [0], 'a', 1, [0], 'a'].replace([1, [0], 'a', 1], [5])

should yield

[5, [0], 'a']

Note that this question is not a duplicate because they do not need to match patterns but only specific items of the list.

like image 362
dylnan Avatar asked Feb 03 '23 23:02

dylnan


1 Answers

a solution that works, replaces the sub-list in-place by using slice assignment:

def replace_list(lst,sublst,replacement):
    lensub = len(sublst)
    i = 0
    while i <= len(lst)-lensub:
        if lst[i:i+lensub] == sublst:
            lst[i:i+lensub] = replacement
            i += len(replacement)
        else:
            i += 1

lst = [1, [0], 'a', 1, [0], 'a']
replace_list(lst,[1, [0], 'a', 1], [5])

now lst is:

[5, [0], 'a']

more complex input (to test end condition & multiple replacements)

lst = [1, [0], 'a', 1, 1, [0], 'a', 1, [0], 'a',1, [0], 'a', 1]

yields once replaced:

[5, 5, [0], 'a', 5]

how it works:

  • loop to slice the list to replace into to the exact size of the sub-list (use while because list changes if replaced into
  • if there's a match, use slice assignment to replace the slice by the replacement & increase counter to avoid overlapping replacements

I'm not too happy about the constant list slicing, but it's needed here to perform equality with the other list, and creating an inner loop would be more cumbersome and not necessarily faster.

If you don't want to work in-place, you could create a copy at start,work on the copy and return it:

def replace_list(lst_,sublst,replacement):
   lst = lst_.copy()
   ...
   return lst
like image 109
Jean-François Fabre Avatar answered Feb 06 '23 14:02

Jean-François Fabre