Перемещение списка списков по индексу в цикле, переформатирование строк
У меня есть список списков, который выглядит так, который был извлечен из плохо отформатированного CSV файла:
DF = [['Customer Number: 001 '],
['Notes: Bought a ton of stuff and was easy to deal with'],
['Customer Number: 666 '],
['Notes: acted and looked like Chris Farley on that hidden decaf skit from SNL'],
['Customer Number: 103 '],
['Notes: bought a ton of stuff got a free keychain'],
['Notes: gave us a referral to his uncles cousins hairdresser'],
['Notes: name address birthday social security number on file'],
['Customer Number: 007 '],
['Notes: looked a lot like James Bond'],
['Notes: came in with a martini']]
Я бы хотел создать новую структуру следующим образом:
['Customer Number: 001 Notes: Bought a ton of stuff and was easy to deal with',
'Customer Number: 666 Notes: acted and looked like Chris Farley on that hidden decaf skit from SNL',
'Customer Number: 103 Notes: bought a ton of stuff got a free keychain',
'Customer Number: 103 Notes: gave us a referral to his uncles cousins hairdresser',
'Customer Number: 103 Notes: name address birthday social security number on file',
'Customer Number: 007 Notes: looked a lot like James Bond',
'Customer Number: 007 Notes: came in with a martini']
после чего я могу разделить, разбить и т.д.
Итак, я использовал факты, которые:
- номер клиента всегда начинается с
Customer Number
-
Notes
всегда длиннее
- число
Notes
никогда не превышает 5
чтобы кодировать то, что явно абсурдное решение, даже если оно работает.
DF = [item for sublist in DF for item in sublist]
DF = DF + ['stophere']
DF2 = []
for record in DF:
if (record[0:17]=="Customer Number: ") & (record !="stophere"):
DF2.append(record + DF[DF.index(record)+1])
if len(DF[DF.index(record)+2]) >21:
DF2.append(record + DF[DF.index(record)+2])
if len(DF[DF.index(record)+3]) >21:
DF2.append(record + DF[DF.index(record)+3])
if len(DF[DF.index(record)+4]) >21:
DF2.append(record + DF[DF.index(record)+4])
if len(DF[DF.index(record)+5]) >21:
DF2.append(record + DF[DF.index(record)+5])
Не возражаете ли вы рекомендовать более стабильное и интеллектуальное решение этой проблемы?
Ответы
Ответ 1
Просто отслеживайте, когда мы находим нового клиента:
from pprint import pprint as pp
out = []
for sub in DF:
if sub[0].startswith("Customer Number"):
cust = sub[0]
else:
out.append(cust + sub[0])
pp(out)
Вывод:
['Customer Number: 001 Notes: Bought a ton of stuff and was easy to deal with',
'Customer Number: 666 Notes: acted and looked like Chris Farley on that '
'hidden decaf skit from SNL',
'Customer Number: 103 Notes: bought a ton of stuff got a free keychain',
'Customer Number: 103 Notes: gave us a referral to his uncles cousins '
'hairdresser',
'Customer Number: 103 Notes: name address birthday social security number '
'on file',
'Customer Number: 007 Notes: looked a lot like James Bond',
'Customer Number: 007 Notes: came in with a martini']
Если клиент может повторить позже, и вы хотите, чтобы они были сгруппированы вместе, используйте dict:
from collections import defaultdict
d = defaultdict(list)
for sub in DF:
if sub[0].startswith("Customer Number"):
cust = sub[0]
else:
d[cust].append(cust + sub[0])
print(d)
Вывод:
pp(d)
{'Customer Number: 001 ': ['Customer Number: 001 Notes: Bought a ton of '
'stuff and was easy to deal with'],
'Customer Number: 007 ': ['Customer Number: 007 Notes: looked a lot like '
'James Bond',
'Customer Number: 007 Notes: came in with a '
'martini'],
'Customer Number: 103 ': ['Customer Number: 103 Notes: bought a ton of '
'stuff got a free keychain',
'Customer Number: 103 Notes: gave us a referral '
'to his uncles cousins hairdresser',
'Customer Number: 103 Notes: name address '
'birthday social security number on file'],
'Customer Number: 666 ': ['Customer Number: 666 Notes: acted and looked '
'like Chris Farley on that hidden decaf skit '
'from SNL']}
Основываясь на ваших комментариях и ошибках, у вас, кажется, есть строки, идущие перед фактическим клиентом, поэтому мы можем добавить их к первому клиенту в списке:
# added ["foo"] before we see any customer
DF = [["foo"],['Customer Number: 001 '],
['Notes: Bought a ton of stuff and was easy to deal with'],
['Customer Number: 666 '],
['Notes: acted and looked like Chris Farley on that hidden decaf skit from SNL'],
['Customer Number: 103 '],
['Notes: bought a ton of stuff got a free keychain'],
['Notes: gave us a referral to his uncles cousins hairdresser'],
['Notes: name address birthday social security number on file'],
['Customer Number: 007 '],
['Notes: looked a lot like James Bond'],
['Notes: came in with a martini']]
from pprint import pprint as pp
from itertools import takewhile, islice
# find lines up to first customer
start = list(takewhile(lambda x: "Customer Number:" not in x[0], DF))
out = []
ln = len(start)
# if we had data before we actually found a customer this will be True
if start:
# so set cust to first customer in list and start adding to out
cust = DF[ln][0]
for sub in start:
out.append(cust + sub[0])
# ln will either be 0 if start is empty else we start at first customer
for sub in islice(DF, ln, None):
if sub[0].startswith("Customer Number"):
cust = sub[0]
else:
out.append(cust + sub[0])
Какие выходы:
['Customer Number: 001 foo',
'Customer Number: 001 Notes: Bought a ton of stuff and was easy to deal with',
'Customer Number: 666 Notes: acted and looked like Chris Farley on that '
'hidden decaf skit from SNL',
'Customer Number: 103 Notes: bought a ton of stuff got a free keychain',
'Customer Number: 103 Notes: gave us a referral to his uncles cousins '
'hairdresser',
'Customer Number: 103 Notes: name address birthday social security number '
'on file',
'Customer Number: 007 Notes: looked a lot like James Bond',
'Customer Number: 007 Notes: came in with a martini']
Я предположил, что вы рассмотрите строки, которые приходят перед любым клиентом, чтобы фактически принадлежать этому первому клиенту.
Ответ 2
Ваша основная цель - группировать заметки и связывать их с клиентом. И поскольку список уже отсортирован, вы можете просто использовать itertools.groupby
, например
from itertools import groupby, chain
def build_notes(it):
customer, func = "", lambda x: x.startswith('Customer')
for item, grp in groupby(chain.from_iterable(DF), key=func):
if item:
customer = next(grp)
else:
for note in grp:
yield customer + note
# In Python 3.x, you can simply do
# yield from (customer + note for note in grp)
Здесь мы сглаживаем фактический список списков в последовательности строк, chain.from_iterable
. И тогда мы группируем строки, в которых есть Customer
, а строки - нет. Если строка имеет Customer
, то item
будет True
иначе False
. Если item
- True
, тогда мы получаем информацию о клиенте, а когда item
- False
, мы перебираем сгруппированные заметки и возвращаем одну строку за раз, объединяя информацию о клиенте с примечаниями.
Итак, когда вы запускаете код,
print(list(build_notes(DF)))
вы получаете
['Customer Number: 001 Notes: Bought a ton of stuff and was easy to deal with',
'Customer Number: 666 Notes: acted and looked like Chris Farley on that hidden decaf skit from SNL',
'Customer Number: 103 Notes: bought a ton of stuff got a free keychain',
'Customer Number: 103 Notes: gave us a referral to his uncles cousins hairdresser',
'Customer Number: 103 Notes: name address birthday social security number on file',
'Customer Number: 007 Notes: looked a lot like James Bond',
'Customer Number: 007 Notes: came in with a martini']
Ответ 3
DF = [['Customer Number: 001 '],
['Notes: Bought a ton of stuff and was easy to deal with'],
['Customer Number: 666 '],
['Notes: acted and looked like Chris Farley on that hidden decaf skit from SNL'],
['Customer Number: 103 '],
['Notes: bought a ton of stuff got a free keychain'],
['Notes: gave us a referral to his uncles cousins hairdresser'],
['Notes: name address birthday social security number on file'],
['Customer Number: 007 '],
['Notes: looked a lot like James Bond'],
['Notes: came in with a martini']]
custnumstr = None
out = []
for df in DF:
if df[0].startswith('Customer Number'):
custnumstr = df[0]
else:
out.append(custnumstr + df[0])
for e in out:
print e
Ответ 4
Вы также можете использовать OrderedDict, где ключи являются клиентами и значениями - это список заметок:
from collections import OrderedDict
DF_dict = OrderedDict()
for subl in DF:
if 'Customer Number' in subl[0]:
DF_dict[subl[0]] = []
continue
last_key = list(DF_dict.keys())[-1]
DF_dict[last_key].append(subl[0])
for customer, notes in DF_dict.items():
for a_note in notes:
print(customer,a_note)
Результаты в:
Customer Number: 001 Notes: Bought a ton of stuff and was easy to deal with
Customer Number: 666 Notes: acted and looked like Chris Farley on that hidden decaf skit from SNL
Customer Number: 103 Notes: bought a ton of stuff got a free keychain
Customer Number: 103 Notes: gave us a referral to his uncles cousins hairdresser
Customer Number: 103 Notes: name address birthday social security number on file
Customer Number: 007 Notes: looked a lot like James Bond
Customer Number: 007 Notes: came in with a martini
Ввод значений в такой dict, может быть полезен, если вы хотите рассчитать, сколько нот для данного клиента, подсчитать заметки или просто выбрать заметки для данного клиента.
Альтернатива, без вызова list(DF_dict.keys())[-1]
на каждой итерации:
last_key = ''
for subl in DF:
if 'Customer Number' in subl[0]:
DF_dict[subl[0]] = []
last_key = subl[0]
continue
DF_dict[last_key].append(subl[0])
И новая более короткая версия, использующая defaultdict:
from collections import defaultdict
DF_dict = defaultdict(list)
for subl in DF:
if 'Customer Number' in subl[0]:
customer = subl[0]
continue
DF_dict[customer].append(subl[0])
Ответ 5
Пока формат совпадает с вашим примером, это должно работать.
final_list = []
for outer_list in DF:
for s in outer_list:
if s.startswith("Customer"):
cust = s
elif s.startswith("Notes"):
final_list.append(cust + s)
for f in final_list:
print f
Ответ 6
Пока вы можете рассчитывать на то, что первый элемент является клиентом, вы можете сделать это следующим образом.
Простой цикл каждого элемента. Если элемент является клиентом, установите текущий клиент в качестве этой строки. Кроме того, это примечание, поэтому вы добавляете клиента и примечание в список результатов.
customer = ""
results = []
for record in DF:
data = record[0]
if "Customer" in data:
customer = data
elif "Notes" in data:
result = customer + data
results.append(result)
print(results)