我有一个宽度有限的文本列,每行都是多个元素的列表,由分号分隔。我想删除导致行传递字符限制的所有列表元素。
以前,我正在使用
if len(row[7].split(';')) > 5:
row[7] = ('; '.join(row[7].split(';')[1:5]).strip())[:45]
这会产生两个明显的问题:
这是一个示例输入:
Foo; Bar; Aoicsdeadwcwewrw; owierwicowmwoemow; aoweirwoer
ODIFUWE
acowierwe; asodicjwoer; s; ow; w; w
这是相应的示例输出:
Foo; Bar; Aoicsdeadwcwewrw
ODIFUWE
acowierwe; asodicjwoer; s; ow; w
限制为5个元素或45个字符,如果该行达到这些限制中的任何一个,则应截断尾随元素。
答案 0 :(得分:2)
我认为这个生成器是确定切割字符串列表的最有效方法:
def limit(iterable, max_num, max_length, padding_length):
seen_length = -padding_length # the first value will not be padded so start negative
for i, s in enumerate(iterable, 1):
if i > max_num or seen_length + padding_length + len(s) > max_length:
return
seen_length += padding_length + len(s)
yield s
像这样使用:
row[7] = "; ".join(limit(row[7].split("; "), 5, 45, 2)
生成器不会加入任何字符串,只是将它们的长度加在一起,因此使用它和join
将是O(N+M)
,其中N
是字符串的数量{{1是结果字符串的长度。这比M
的解决方案更好,因为重复的gnibbler
s导致O(N*M)
。对于相对较短且很少的字符串,这种算法改进可能并不重要,就像你描述的那样,但是如果你试图限制说话,500个项目和数千个字符的长度,你可能会注意到差异。 / p>
答案 1 :(得分:1)
>>> data = """ Foo; Bar; Aoicsdeadwcwewrw; owierwicowmwoemow; aoweirwoer
... ODIFUWE
... acowierwe; asodicjwoer; s; ow; w; w""".split("\n")
>>>
>>> for row in data:
... row = row.split(";")[:5]
... res = []
... for item in row:
... if len(";".join(res + [item])) > 45: break
... res.append(item)
... print ";".join(res)
...
Foo; Bar; Aoicsdeadwcwewrw
ODIFUWE
acowierwe; asodicjwoer; s; ow; w
答案 2 :(得分:1)
这是一个功能性故障,它应该使事情变得更加明显:
data = [
" Foo; Bar; Aoicsdeadwcwewrw; owierwicowmwoemow; aoweirwoer",
" ODIFUWE",
" acowierwe; asodicjwoer; s; ow; w; w"
]
def first_n_chars(s, break_on, n):
if len(s) > n:
return s[:s.rfind(break_on, 0, n + len(break_on))]
else:
return s
def first_n_groups(s, break_on, n):
try:
end = -1
for _ in range(n):
end = s.index(break_on, end+1)
return s[:end]
except ValueError:
return s
fortyfivechars = (first_n_chars (s, '; ', 45) for s in data)
fivegroups = (first_n_groups(s, '; ', 5) for s in fortyfivechars)
trimmed_data = list(fivegroups)
导致
[' Foo; Bar; Aoicsdeadwcwewrw',
' ODIFUWE',
' acowierwe; asodicjwoer; s; ow; w']
答案 3 :(得分:0)
def myfilter(x, wmax=5, cmax=45, d=';'):
words = x.split(d)
nwords = 0
nchars = 0
s = []
for i in words:
nwords += 1
nchars += len(i) + len(d)
if (nwords >= wmax) | (nchars > cmax+1):
break
s.append(i)
return ';'.join(s)
这样的事情应该有效。