簡體   English   中英

按字符和元素的切片列表,Python

[英]Slicing list by characters and elements, Python

我有一個寬度有限的文本列,並且每一行都是由分號分隔的多個元素的列表。 我想刪除所有導致該行通過字符數限制的列表元素。

以前我在用

   if len(row[7].split(';')) > 5:
        row[7] = ('; '.join(row[7].split(';')[1:5]).strip())[:45]

這產生了兩個明顯的問題:

  • 有些列表的元素少於5個,字符數超過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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM