LINUX.ORG.RU

Как превратить линейный список в список списков (таблицу)?

 


0

1

Есть список строк:

list1 = '''1
первое название
2:23
автор такой-то
2
следующее название
1:09
автор сякой-то'''.split('\n')

(Разумеется, строк гораздо больше.) Нужно превратить его в «таблицу»:

[['1', 'первое название',   '2:23', 'автор такой-то'],
 ['2', 'следующее название', '1:09', 'автор сякой-то']]

Желательно список списков, а не список кортежей, чтобы было проще менять элементы. Число строк кратно 4, либо можно отбросить лишние.

Почти сразу нашёл в сети красивое решение:

list2 = list( zip( * [iter(list1)] * 4 ) )

которое даёт именно список кортежей. Можно сделать

list2 = [ list(_) for _ in zip( * [iter(list1)] * 4 ) ]

Но как-то некрасиво.

Более правильные решения есть?

Ответ-однострочник:

list2 = list( map( list, zip( * [iter(list1)] * 4 ) ) )
★★★★★

Последнее исправление: question4 (всего исправлений: 2)
[[*arg] for arg in zip(*(list1[i:] for i in range(4)))]
thunar ★★★★★
()
Последнее исправление: thunar (всего исправлений: 2)
Ответ на: комментарий от Zeta_Gundam

grouper

Он тоже возвращает список кортежей.

question4 ★★★★★
() автор топика

Более правильным будет поменять формат входных данных, если это возможно. Такие выборки по 4 элемента это жуткая жуть, одна лишняя пустая строка в середине и все превращается в тыкву.

Кроме \n есть еще много разделителей;-)

А так генератор конечно же, вариантов много, это же питон.

AntonI ★★★★★
()
Ответ на: комментарий от AntonI

поменять формат входных данных

Копируется вручную с веб-страницы, извлекается pyperclip-ом.

лишняя пустая строка в середине

Не бывает. А вот нечисловой текст в 1-й колонке встречается.

question4 ★★★★★
() автор топика
Ответ на: комментарий от question4

Не бывает.

Ну тогда лишний элемент (один). Все что может испортиться - портится. В общем контроль делимости на четыре я бы как минимум вставил.

А вот нечисловой текст в 1-й колонке встречается.

Это как раз небольшая проблема. Если это обработка ручной копипасты, то скрипт может спрашивать что делать в интерактиве в таких случаях.

AntonI ★★★★★
()
Ответ на: комментарий от question4

лучше сразу стараться делать нормально и не мучиться.

потом у тебя пойдут костыли в виде artist = list2[0][3] вместо list2.get('artist')

usi_svobodi
()
Ответ на: комментарий от moonmadness

На курсах вайтивайти с ноги вертушкой на петоне циклам не учат

no-dashi-v2 ★★★
()
Ответ на: комментарий от moonmadness

Можно. list1 = pyperclip.paste().split('\n'); list2 = [ [ list1[p*4+q] ] for q in range(4) ] for p in range(len(list1)//4) ] Но неинтересно.

question4 ★★★★★
() автор топика
Ответ на: комментарий от moonmadness

С этой всей функциональщиной люди забудут как писать обычные циклы вроде while(!eof) {val = read(); process(val);}.

X512 ★★★★★
()
Ответ на: комментарий от moonmadness

Это ж питон. Звучит странно, но оптимальным вариантом будет чуть ли не создание numpy матрицы с помощью генератора, итерирующего по списку.

Shadow ★★★★★
()
Ответ на: комментарий от Shadow

Одна из самых медленных вещей в мире - обычные циклы в python.

Есть вещи ещё медленнее. В этом цикле можно добавлять по 1 элементу в питоновский список.

question4 ★★★★★
() автор топика
Ответ на: комментарий от Shadow

Звучит странно, но оптимальным вариантом будет чуть ли не создание numpy матрицы с помощью генератора, итерирующего по списку.

Средствами numpy задача решается элементарно.

np.array(list1)[:len(list1) - len(list1) % 4].reshape(len(list1)//4,4)

Можно даже присвоить имена столбцам, только тогда придётся руками выставить длины строк.

Но мне сейчас интереснее узнать о других способах.

question4 ★★★★★
() автор топика
Ответ на: комментарий от ei-grad

Или

list( map( list, zip( * [iter(list1)] * 4 ) ) )

Спасибо!

question4 ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.