5

假设我们需要一个程序,它接受一个字符串列表并将它们拆分,并将前两个单词以元组的形式附加到一个列表并返回该列表;换句话说,一个程序可以为您提供每个字符串的前两个单词。

input: ["hello world how are you", "foo bar baz"]
output: [("hello", "world"), ("foo", "bar")]

可以这样写(我们假设输入有效):

def firstTwoWords(strings):
    result = []
    for s in strings:
        splt = s.split()
        result.append((splt[0], splt[1]))
    return result

但是列表理解会更好。

def firstTwoWords(strings):
    return [(s.split()[0], s.split()[1]) for s in strings]

但这涉及到两次调用split(). 有没有办法在理解范围内只执行一次拆分?我尝试了自然而然的方法,但语法无效:

>>> [(splt[0],splt[1]) for s in strings with s.split() as splt]
  File "<stdin>", line 1
    [(splt[0],splt[1]) for s in strings with s.split() as splt]
                                           ^
SyntaxError: invalid syntax
4

6 回答 6

6

好吧,在这种特殊情况下:

def firstTwoWords(strings):
    return [s.split()[:2] for s in strings]

但是,否则,您可以使用一个生成器表达式:

def firstTwoWords(strings):
    return [(s[0], s[1]) for s in (s.split() for s in strings)]

如果性能实际上很关键,只需使用一个函数。

于 2013-07-10T01:19:40.190 回答
4

不幸的是,写下从英语中自然想到的东西并希望它是有效的语法很少奏效。

您尝试做的通用形式是将某些表达式绑定到理解中的名称。对此没有直接支持,但由于推导式中的for子句依次将名称绑定到序列中的每个元素,因此您可以使用for单元素容器来实现相同的效果:

>>> strings = ["hello world how are you", "foo bar baz"]
>>> [(splt[0],splt[1]) for s in strings for splt in [s.split()]]
[('hello', 'world'), ('foo', 'bar')]
于 2013-07-10T01:29:09.347 回答
2

minitech 的答案是正确的方法。

但是请注意,您不必在一行中完成所有操作,并且您并没有真正获得任何收益。

这个:

splits = (s.split() for s in strings)
return [(s[0], s[1]) for s in splits]

与此完全相同:

return [(s[0], s[1]) for s in (s.split() for s in strings)]

没有额外的中间值被构建,对垃圾收集没有影响,只是免费提供了更多的可读性。

此外,您的真实代码很可能最终实际上并不需要一个列表,而只是一些可迭代的东西,在这种情况下,您最好这样做:

splits = (s.split() for s in strings)
return ((s[0], s[1]) for s in splits)

或者,在 Python 3.3+ 中:

splits = (s.split() for s in strings)
yield from ((s[0], s[1]) for s in splits)

事实上,很多程序都可以用这种方式编写——一系列生成器表达式,然后是return最后yield from一个geneexpr/listcomp。

于 2013-07-10T01:42:35.350 回答
2

我认为使用 genexp 更好,但这里是如何使用lambda. 在某些情况下,这可能更合适

>>> [(lambda splt:(splt[0], splt[1]))(s.split()) for s in input]
[('hello', 'world'), ('foo', 'bar')]
于 2013-07-10T01:29:19.350 回答
1

像这样?

def firstTwoWords(strings):
    return [s.split()[:2] for s in strings]

它使用列表拼接。它当然会返回一个列表,但如果你想要一个元组,你可以使用:

def firstTwoWords(strings):
    return [tuple(s.split()[:2]) for s in strings]
于 2013-07-10T01:19:03.770 回答
0

itemgetter可以在这里使用。它比s.split()[:2]. 它允许您将任意项目拉出s

>>> from operator import itemgetter
>>> strings = ["hello world how are you", "foo bar baz"]
>>> [itemgetter(0, 1)(s.split()) for s in strings]
[('hello', 'world'), ('foo', 'bar')]

更普遍:

>>> [itemgetter(1, 2, 0)(s.split()) for s in strings]
[('world', 'how', 'hello'), ('bar', 'baz', 'foo')]
于 2015-08-29T11:34:22.217 回答