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

时间:2014-02-10 01:07:52

标签: python list python-2.7 csv slice

我有一个宽度有限的文本列,每行都是多个元素的列表,由分号分隔。我想删除导致行传递字符限制的所有列表元素。

以前,我正在使用

   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个字符,如果该行达到这些限制中的任何一个,则应截断尾随元素。

4 个答案:

答案 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)

这样的事情应该有效。