在保留原始列表顺序的同时拆分列表中的字符串

时间:2012-01-08 20:03:17

标签: python string list

我想做一些有点棘手的事情,我不确定最好的方法。

我有一个二维数组,其形式为嵌套列表。列表中的每个“行”具有以下结构:

['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'

对于这种情况,我想插入一个占位符来保留数组中每个元素的位置(以便最终位置的数字始终具有相同的索引)。

我正在使用的数组相当大,超过10万行。任何帮助都会非常感激,因为我真的很挣这个。

6 个答案:

答案 0 :(得分:2)

如果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())

Example

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 :(得分:1)

如果你循环浏览它,每次都要点击'..';你可以在一个新的列表中将所有内容连接起来。我不认为有一个更简单的解决方案。然而,速度不是我的专长。

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, [])

我不太清楚代码中“Thing”的重要性,或者为什么它没有出现在输出中。如果你解释它的规则,我会更新我的答案。

答案 2 :(得分:0)

我不认为我真的理解这个问题......但希望这会给你一个提示:

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

答案 3 :(得分:0)

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) 

更新:这是timeit所说的:

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 ..'就完全相同。

答案 4 :(得分:0)

尝试运行此代码:

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个元素,则甚至用占位符填充。

答案 5 :(得分:0)

这个版本做了很多检查:

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