Алгоритм конкатенации списка строк зигзагообразным способом - PullRequest
2 голосов
/ 27 апреля 2020

У меня есть следующая проблема: из списка строк мне нужно взять первые буквы из всех строк, после (сзади) я должен взять вторые буквы, после третьих букв спереди конец и т. д.

Пример ввода:

['abcd', 'efgh', 'ijkl', 'mnop']

Вывод должен быть:

'aeimnjfbcgkoplhd'

Здесь я до сих пор, первый «для» добавляется к массив: aeim и cgko, второй «для» добавляет к массиву: njfb и plhd. В любом случае, заказ не очень хороший, мне нужен aeim + njfb + cgko + plhd

array = []
if len(list_of_strings[0]) % 2 == 0: # if we have strings with even number of letters
    for j in range(len(list_of_strings[0]/2)): # range(2) in our example
        for i in range(len(list_of_strings)): # range(4) in our example
            array.append(list_of_strings[i][j*2])

    for j in range(1, len(list_of_strings[0]), 2): # range(1, 4, 2) in our example
        for i in range(len(list_of_strings) - 1, -1, -1): # range(3, -1, -1) in our example
            array.append(list_of_strings[i][j])

Пожалуйста, помогите.

Спасибо

Ответы [ 2 ]

5 голосов
/ 27 апреля 2020

Вы можете использовать простой однострочник, используя "распаковать" (т.е. zip(*a)) и str.join:

a = ['abcd', 'efgh', 'ijkl', 'mnop']
b = ''.join(''.join(t[::1-2*(i%2)]) for i, t in enumerate(zip(*a)))
assert b == 'aeimnjfbcgkoplhd'

join может принимать выражение генератора в качестве аргумента, в этом случае выражение генератора равно

''.join(t[::1-2*(i%2)]) for i, t in enumerate(zip(*a))

Выражение

zip(*a)

распаковывает строки в a, т.е. он возвращает генератор, который выдает кортежи, содержащие все первые буквы, все вторые буквы и т. д. c. каждой строки.

Индексация в

t[::1-2*(i%2)]

гарантирует, что мы будем изменять порядок кортежей каждую 2-ю итерацию.


EDIT

Я сравнил свой однострочный ответ с ответом @ cs95 , и производительность обоих полей остается одинаковой в пределах ошибки. Я думаю, что в «реальном коде» я бы предпочел его решение для большей ясности.

4 голосов
/ 27 апреля 2020

Думайте о символах как об элементах в двумерном массиве:

a b c d
e f g h
i j k l
m n o p

Мы хотим go увеличить вниз по нечетным столбцам, затем увеличить по четным столбцам, поэтому мы делаем что-то вроде этого:

chars = []
for i in range(len(l[0])):
    for w in l[::1 if i  % 2 == 0 else -1]:  
        chars.append(w[i])
print(''.join(chars))
# aeimnjfbcgkoplhd

l[::1 if i % 2 == 0 else -1] перевернет список для четных столбцов, поэтому мы выбираем символы с конца. Это интуитивно понятно, но безобразно, так как разрезание списка создает неглубокую копию. Мы можем сделать что-то более умное, используя мод, чтобы определить, следует ли выполнять итерацию в обратном порядке:

chars = []
for i in range(len(l[0])):
    for j in range(len(l)) if i % 2 == 0 else reversed(range(len(l))):
        chars.append(l[j][i])
print(''.join(chars))
# aeimnjfbcgkoplhd
...