[英]Slicing list by characters and elements, Python
我有一個寬度有限的文本列,並且每一行都是由分號分隔的多個元素的列表。 我想刪除所有導致該行通過字符數限制的列表元素。
以前我在用
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個字符,如果行達到這些限制中的任何一個,則尾隨的元素應被切除。
我認為此生成器是確定在哪里剪切字符串列表的最有效方法:
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
是字符串數, M
是結果字符串的長度。 這是優於gnibbler
的解決方案,這是O(N*M)
由於反復join
秒。 對於您所描述的相對較短和較少的字符串,這種算法上的改進可能並不重要,但是如果您試圖限制要說的東西(500個項目和數千個字符的長度),則可能會注意到其中的區別。
>>> 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
這是功能細分,應該使發生的事情更明顯:
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']
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)
這樣的事情應該起作用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.