How to remove a character from every string in a list, based on the position where a specific character occurs in the first member of said list?

Viewed 143

So I have a list of strings, all with the same length, like this:

list_strings=["A-C-TG--","ATCGTAGC","ATGCGATC","ATGCGGTC"]

What I'm trying to do is, for each position where the first member of list_strings has a "-", remove every character in those same positions from every member of list_strings.

My output would be something like this:

new_list_strings=["ACTG","ACTA","AGGA","AGGG"]

I've tried doing this:

  1. Creating an empty new list.
  2. Getting the positions where the first member of list_strings has a "-".
  3. Remove the gap from all the strings and append the new string to "new_list_strings"
list_strings=["A-C-TG--","ATCGTAGC","ATGCGATC","ATGCGGTC"]
new_list_strings=[]
positions=[i for i, letter in enumerate(list_strings[0]) if letter == "-"]
for string in list_strings:
    for i in range(len(string)):
        for pos in positions:
            if i==pos:
                string2=string[:i]+string[i+1:]
                new_list_strings.append(string2)

Unfortunately, this is only removing on one of the positions and not all of them. Anyone knows what I'm doing wrong?

3 Answers

Solution using zip()

>>> shortened = [*zip(*[t for t in zip(*list_strings) if t[0] != "-"])]
>>> shortened
[('A', 'C', 'T', 'G'), ('A', 'C', 'T', 'A'), ('A', 'G', 'G', 'A'), ('A', 'G', 'G', 'G')]
>>>
>>> new_strings = ["".join(t) for t in shortened]
>>> new_strings
['ACTG', 'ACTA', 'AGGA', 'AGGG']

So, there are plenty of ways to do this, but this particular method zips the gene strings together and filters out the tuples which start with a "-". Think of stacking the four gene strings on top of each other: zip() takes the "columns" of that stack:

>>> [*zip(*list_strings)]
[('A', 'A', 'A', 'A'), ('-', 'T', 'T', 'T'), ('C', 'C', 'G', 'G'), ('-', 'G', 'C', 'C'), ('T', 'T', 'G', 'G'), ('G', 'A', 'A', 'G'), ('-', 'G', 'T', 'T'), ('-', 'C', 'C', 'C')]

After removing the tuples that start with "-", the tuples are zipped back together the other way (think now of taking these tuples and stacking them vertically, then in the same way as before, zip() takes the columns of that stack). Finally, "".join() turns the tuples of characters into strings.

"What am I doing wrong?"

To answer the question "what am I doing wrong?", I've added print statements to your code. Try running this and interpreting the output:

list_strings=["A-C-TG--","ATCGTAGC","ATGCGATC","ATGCGGTC"]
new_list_strings=[]
positions=[i for i, letter in enumerate(list_strings[0]) if letter == "-"]

for string in list_strings:
    print(f"string: {string}")
    for i in range(len(string)):
        print(f"    i: {i}")
        for pos in positions:
            print(f"        pos: {pos}")
            if i==pos:
                string2=string[:i]+string[i+1:]
                print(f"            match! string2 result: {string2}")
                new_list_strings.append(string2)
    print()

Notice that for each string, multiple string2 objects are created.

Solution using a plain-Jane accumulator pattern

The barebones accumulator pattern does work for this problem:

list_strings = ["A-C-TG--","ATCGTAGC","ATGCGATC","ATGCGGTC"]
positions = [i for i, letter in enumerate(list_strings[0]) if letter == "-"]

new_list_strings = []
for string in list_strings:
    new_str = ""
    for idx, char in string:
        if idx not in positions:
            new_str += char
    new_list_strings.append(new_str)

Here's one way to do it:

list_strings=["A-C-TG--","ATCGTAGC","ATGCGATC","ATGCGGTC"]
new_list_strings=[]
positions=[i for i, letter in enumerate(list_strings[0]) if letter == "-"]

# Hack so I can handle the first pos like the others
positions = [-1] + positions
# positions is now [-1, 1, 3, 6, 7]

for string in list_strings:
    string2 = ''
    for j, pos in enumerate(positions):
        # Get segment between current pos and the previous one
        string2 += string[positions[j-1]+1:pos]
    new_list_strings.append(string2)

itemgetter (from the operator library).

>>> from operator import itemgetter
>>> L=["A-C-TG--","ATCGTAGC","ATGCGATC","ATGCGGTC"]
>>> idx = [i for i,v in enumerate(L[0]) if v != '-']
>>> for item in L:
    print(''.join(itemgetter(*idx)(item)))

    
ACTG
ACTA
AGGA
AGGG
Related