Разделить строку в списке при сохранении оригинального порядка списка - PullRequest
1 голос
/ 09 января 2012

Я хотел бы сделать что-то немного сложнее, и я не уверен, что лучший способ сделать это.

У меня есть двумерный массив, который находится в форме вложенного списка. Каждая «строка» в списке имеет следующую структуру:

['171000', 'Thing..Mega~Corporate~Thing..Mid~Dairy~Thing..Micro~Cheese', 'Cheese', '0.012174']

Я хотел бы сделать цикл по всему массиву, строка за строкой, и создать новую строку, которая разбивает строку во второй позиции на три новые строки в списке, так что результат будет следующим:

['171000', 'Mega~Corporate', 'Mid~Dairy', 'Micro~Cheese', 'Cheese', '0.012174']

Несколько вещей, которые я должен упомянуть. В приведенном выше случае я разделил строку на три подстроки: Mega, Mid, Micro. Не каждая строка будет иметь «Mid» и «Micro» часть. Некоторые из этих строк могут быть просто более короткими версиями того же формата:

'Thing..Mega~Corporate'

Для этого случая я хотел бы вставить заполнитель, чтобы сохранить позицию каждого элемента в массиве (чтобы числа в конечной позиции всегда имели одинаковый индекс).

Массив, с которым я работаю, довольно большой, более 100 000 строк. Любая помощь будет принята с благодарностью, так как я действительно борюсь с этим.

Ответы [ 6 ]

2 голосов
/ 09 января 2012

Если Thing.. представляет произвольный текст (не буквальные данные в строке):

import re

def explode(s, keywords):
    for k in keywords:
        m = re.search(r'(%s~[^~]*)(?:~|$)' % (re.escape(k),), s)
        yield m and m.group(1)

for row in lst:
    row[1:2] = explode(row[1], "Mega Mid Micro".split())

Пример

import re
from pprint import pprint

def explode(s, keywords):
    for k in keywords:
        m = re.search(r'(%s~[^~]*)(?:~|$)' % (re.escape(k),), s)
        yield m and m.group(1)


lst = [
 ['171000', 'Thing..Mega~Corporate~Thing..Mid~Dairy~Thing..Micro~Cheese', 'Cheese', '0.012174'],
 ['171000', 'Thing..Mega~Corporate', 'Cheese', '0.012174'],
]

print("Before:")
pprint(lst)

for row in lst:
    row[1:2] = explode(row[1], "Mega Mid Micro".split())

print("\nAfter:")
pprint(lst)

выход

Before:
[['171000',
  'Thing..Mega~Corporate~Thing..Mid~Dairy~Thing..Micro~Cheese',
  'Cheese',
  '0.012174'],
 ['171000', 'Thing..Mega~Corporate', 'Cheese', '0.012174']]

After:
[['171000',
  'Mega~Corporate',
  'Mid~Dairy',
  'Micro~Cheese',
  'Cheese',
  '0.012174'],
 ['171000', 'Mega~Corporate', None, None, 'Cheese', '0.012174']]
1 голос
/ 09 января 2012

Если вы пройдете через него, каждый раз разделяясь на «..»;Вы можете объединить все вместе в новом списке.Я не думаю, что есть намного более простое решение.Скорость, однако, не моя специальность.

row = ['171000', 'Thing..Mega~Corporate~Thing..Mid~Dairy~Thing..Micro~Cheese', 'Cheese', '0.012174']
new_row = []
for i in row: 
    new_row += i.split('..')

Конечный результат ...

['171000', 'Thing', 'Mega~Corporate~Thing', 'Mid~Dairy~Thing', 'Micro~Cheese', 'Cheese', '0.012174']

Если вы не хотите использовать дополнительную переменную, другуюспособ сделать это - использовать reduce.

row = reduce(lambda x, y: x + y.split('..'), row, [])

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

0 голосов
/ 09 января 2012

Эта версия много проверяет:

def explode_strg(strg):
    temp = strg.split('~')
    npieces = len(temp)
    assert npieces in (6, 4, 2)
    result = ['', '', '']
    prefix = 'Thing..'
    for i in xrange(0, npieces, 2):
        k = temp[i]
        v = temp[i+1]
        assert k.startswith(prefix)
        k = k[len(prefix):]
        j = i // 2
        assert k == ('Mega', 'Mid', 'Micro')[j]
        result[j] = k + '~' + v
    return result

tests = [
    ('Thing..Mega~Corporate~Thing..Mid~Dairy~Thing..Micro~Cheese', ['Mega~Corporate', 'Mid~Dairy', 'Micro~Cheese']),
    ('Thing..Mega~Corporate~Thing..Mid~Dairy',                     ['Mega~Corporate', 'Mid~Dairy', '']),
    ('Thing..Mega~Corporate',                                      ['Mega~Corporate', '', '']),
    ]

for s, elist in tests:
    alist = explode_strg(s)
    print alist == elist, s, alist
0 голосов
/ 09 января 2012

Попробуйте запустить этот код:

import re

row = ['171000', 'Thing..Mega~Corporate~Thing..Mid~Dairy~Thing..Micro~Cheese', 'Cheese', '0.012174']

Теперь для каждой строки:

col2 = re.split(r'~?Thing\.\.', row[1])[1:]
row[1:2] = col2 + ['placeholder'] * (3 - len(col2))

После последней строки, row будет таким, как вы просили, даже заполняя заполнителями, если вторая позиция содержит менее 3 элементов после ее разделения.

0 голосов
/ 09 января 2012

FakeRainBrigand уже прибил его, кроме случаев, когда '..' появляется в других элементах. Несмотря на это, мне было бы любопытно сравнить время, чтобы увидеть, насколько плоха эта идея, что также технически более правильно:

for row in myfile:
  toSplit = row.pop(1)  # 1 being the position of the string to manipulate
  for fragment in toSplit.split('..'):
    row.insert(-2,fragment) 

ОБНОВЛЕНИЕ: это то, что время говорит:

s1 = """myfile = [ ['171000', 'Mega~Corporate~Thing..Mid~Dairy~Thing..Micro~Cheese', 'Cheese', '0.012174'] for i in xrange(1,10000) ]
for row in myfile:
  toSplit = row.pop(1)
  for fragment in toSplit.split('..'):
    row.insert(-2,fragment)
"""
s2 = """myfile = [ ['171000', 'Mega~Corporate~Thing..Mid~Dairy~Thing..Micro~Cheese', 'Cheese', '0.012174'] for i in xrange(1,10000) ]
for row in myfile:
  new_row = []
  for i in row: 
    new_row += i.split('..')
"""
>>> t1 = timeit.Timer(stmt=s1)
>>> t2 = timeit.Timer(stmt=s2)
>>> print "%.2f usec/pass" % (1000000 * t1.timeit(number=1000)/100000)
166.36 usec/pass
>>> print "%.2f usec/pass" % (1000000 * t2.timeit(number=1000)/100000)
214.22 usec/pass

Оба не очень быстрые, я уверен, что мы можем добиться большего. Я ожидаю, что любое решение на основе регулярных выражений будет медленнее. Обратите внимание, что разделение на «..» или разделение на «~ Thing ..» в точности эквивалентны, если строка остается неизменной на протяжении всей операции.

0 голосов
/ 09 января 2012

Не думаю, что я действительно понимаю вопрос ... но, надеюсь, это даст вам подсказку:

l = ['171000', 'Mega~Corporate~Thing..Mid~Dairy~Thing..Micro~Cheese', 'Cheese', '0.012174']

strs = l[1].split('..')
l = [l[0]] + strs + l[2:]
print l
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...