【问题标题】:Ellipsizing list joins, Pythonically椭圆化列表连接,Pythonically
【发布时间】:2014-06-03 17:09:57
【问题描述】:

几天前我了解了列表推导,现在我觉得我对它们有点疯狂,试图让它们解决所有问题。也许我还没有真正理解它们,或者我对 Python 的了解还不够,无法让它们既强大又简单。这个问题已经困扰了我一段时间,如果有任何意见,我将不胜感激。

问题

在 Python 中,将字符串列表 words 加入到满足这些条件的单个字符串 excerpt 中:

  • 单个空格分隔元素
  • excerpt的最终长度不超过整数maximum_length
  • 如果words 的所有元素都不在excerpt 中,则将省略号字符 附加到excerpt
  • 只有words 的整个元素出现在excerpt

丑陋的解决方案

words = ('Your mother was a hamster and your ' +
         'father smelled of elderberries!').split()
maximum_length = 29
excerpt = ' '.join(words) if len(' '.join(words)) <= maximum_length else \
          ' '.join(words[:max([n for n in range(0, len(words)) if \
                               len(' '.join(words[:n]) + '\u2026') <= \
                               maximum_length])]) + '\u2026'
print(excerpt)      # Your mother was a hamster…
print(len(excerpt)) # 26

是的,这行得通。 Your mother was a hamster and 适合 29,但没有为省略号留下空间。但是男孩是丑陋的。我可以稍微分解一下:

words = ('Your mother was a hamster and your ' +
         'father smelled of elderberries!').split()
maximum_length = 29
excerpt = ' '.join(words)
if len(excerpt) > maximum_length:
    maximum_words = max([n for n in range(0, len(words)) if \
                         len(' '.join(words[:n]) + '\u2026') <= \
                         maximum_length])
    excerpt = ' '.join(words[:maximum_words]) + '\u2026'
print(excerpt)  # 'Your mother was a hamster…'

但现在我创建了一个我永远不会再使用的变量。好像很浪费。而且它并没有真正让任何东西变得更漂亮或更容易理解。

有没有更好的方法来做到这一点,我只是还没有见过?

【问题讨论】:

  • 看起来你对列表理解发疯是对的。记住python的禅:“3.简单胜于复杂”。我花了 10 秒来理解问题,但花了 5 分钟来理解你的代码。不要对线条和变量过于节俭。你需要打动的不是 python,而是稍后会维护你的代码的人。
  • 如果我必须使用 listcomps 解决这个问题,我会使用 textwrap 模块。 (但那不会使用 listcomps!--ed。仔细重读我的第一句话。--dsm)
  • @DSM - textwrap.shorten 看起来完全符合我的要求,前提是 words 中的所有元素都不包含空格,在这种情况下,我可能会得到一个部分元素。不过,我没有在问题中具体说明这种可能性,因为我只是在阅读答案时才想到。

标签: python string list join


【解决方案1】:

请参阅我关于“简单胜于复杂”的评论

也就是说,这里有一个建议

l = 'Your mother was a hamster and your father smelled of elderberries!'

last_space = l.rfind(' ', 0, 29)

suffix = ""
if last_space < 29:
  suffix = "..."

print l[:last_space]+suffix

这不是你需要的 100%,而是很容易扩展

【讨论】:

  • 当你只搜索l[0:29]时,last_space的索引总是小于29...
  • 你是对的,实际上它需要检查-1,这意味着“未找到”。我只是想提出一个方向,而不是一个完整的解决方案。
  • 如果字符串短于 29 则不起作用,它只会修剪最后一个单词
  • 一个可行的解决方案是if len(l) &gt; 29: print l[:l.rfind(' ', 0, 27)]+'...'
【解决方案2】:

我的拙见是,您在该任务中不需要列表理解是正确的。我会首先通过拆分获取列表中的所有单词,然后可能会执行一个 while 循环,从列表末尾一次删除一个单词,直到 len(' '.join(list))

我还将 maximum_length 缩短 3(省略号的长度),在 while 循环结束后,添加“...”作为列表的最后一个元素。

【讨论】:

    【解决方案3】:

    您可以将excerpt 修剪为maximum_length。然后,使用rsplit 删除最后一个空格并附加到省略号上:

    def append_ellipsis(words, length=29):
        excerpt = ' '.join(words)[:length]
    
        # If you are using Python 3.x then you can instead of the line below,
        # pass `maxsplit=1` to `rsplit`. Below is the Python 2.x version.
        return excerpt.rsplit(' ', 1)[0] + '\u2026'
    
    words = ('Your mother was a hamster and your ' +
             'father smelled of elderberries!').split()
    
    result = append_ellipsis(words)
    print(result)
    print(len(result))
    

    【讨论】:

    • 无论最后一个字符是否为空格,您都应该可以使用rsplit
    • @Peter The Python documentation 表明 rsplit 接受关键字参数(至少可以追溯到 2.6 并且与 dev 3.5 一样最新)
    • rsplit 在 2.x 中确实接受参数,但它不接受 keyword 参数 - 您必须使用 rsplit(' ', 1)rsplit(None, 1)
    • @DarinDouglass 啊好吧不知道。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-09
    • 2012-02-11
    • 2014-01-02
    • 2014-09-13
    • 1970-01-01
    • 2017-05-04
    • 1970-01-01
    相关资源
    最近更新 更多