Python列表推导式:返回字符串列表而不是列表的列表。

3

为了完成一项作业任务,我们需要创建一个函数,该函数接受两个输入(列表和字符串),并返回一个列表。我希望使用列表推导式来编写此函数,但是一直遇到一个烦人的问题。以下是我想要重新编写的原始函数:

index = [['keyword1', ['url1', 'url2', 'url3']], ['keyword2', ['url4', 'url5']]...]

def lookup(index, keyword):
    result = []
    for entry in index:
        if entry[0] == keyword:
            result += entry[1]
    return result

以下是我尝试使用列表推导的结果:

def lookup(index, keyword):
    return [entry[1] for entry in index if entry[0] == keyword]

def lookup(index, keyword):
    return [ulist for key, ulist in index if i == keyword]

最后...

def lookup(index, keyword):
    return [j for j in (entry[1] for entry in index if entry[0] == keyword)]

这里的问题是它返回的所需URL在一个列表中,而这个列表又在另一个列表里,像这样:
[['url1', 'url2', 'url3']]

期望的格式是:

['url1', 'url2', 'url3']

我想只需这样做(在返回语句结尾添加 [0] 以便给出内部列表):
def lookup(index, keyword):
        return [j for j in (entry[1] for entry in index if entry[0] == keyword)][0]

但这似乎不是正确的方法。我是否试图不必要地使用列表推导式(我的理解是,这种情况非常适合使用列表推导式)?有什么建议吗?

6个回答

7
这将是最直接的方法:
def lookup(index,keyword):
    return [x for entry in index if entry[0]==keyword for x in entry[1]]

嵌套列表推导式的语法可能不是您最初期望的那样。关键在于要意识到使用两个for循环不是两个单独的列表推导式,而是一个具有嵌套循环的列表推导式。这实际上就是它能够工作的原因。就像您正在编写的代码一样。
for entry in index:
  if entry[0]==keyword:
    for x in entry[1]:
      yield x

列表推导式中的顺序与普通循环相同,只是首先返回产生的值。


当我第一次阅读时,我认为它会生成:"UnboundLocalError: local variable 'x' referenced before assignment"。但是当我尝试了这个:[j for j in entry[1] for entry in index if entry[0] == keyword],我得到了这个错误。在这些类型的表达式中,赋值是否有所不同? - Verbal_Kint
非常有帮助!当您以这种方式说明时,第一个变量似乎显然正在以与生成的值相同的方式构建列表。区别仅在于将其作为列表推导语法所需的第一个值呈现。太棒了! - Verbal_Kint

3

你应该使用字典,因为它的API更适合处理与地图相关的内容,并且可以快速处理。

keywordToUrl = {keyword1:(url1,url2,url3), keyword2:(url4,url5), ...}
keywordToUrl[keyword]

1
我应该明确指出这个任务只能使用列表。对于造成的困惑,我很抱歉... - Verbal_Kint
1
我永远不会理解为什么老师和教授会设计这样愚蠢的作业。 - Karl Knechtel

1
def lookup(index, keyword):
    return sum((entry[1] for entry in index if entry[0] == keyword), [])

例子:

>>> index = [['keyword1', ['url1', 'url2', 'url3']], ['keyword2', ['url4', 'url5']]]
>>> lookup(index, 'keyword1')
['url1', 'url2', 'url3']

0

让我们以这个例子为例:当我提供一个字母和一个列表时,返回函数将给出以该字母开头的列表中存在的名称。

def abc(letter , nameslist):
    return [name for name in nameslist if name[0].lower() == letter.lower() ]


nameslist = ["Sou", "Soudipta", "Gini", "Protijayi", "Gina"]

print( abc("P",nameslist) )

0
def lookup(index,keyword):
    return [j for j in (entry[1] for entry in index if entry[0] == keyword)]

问题在于你在括号内返回了某个值,因此你的值被返回到了一个列表中,去掉括号就可以解决这个问题了。
以下是正确的代码:
def lookup(index,keyword):
    return j for j in (entry[1] for entry in index if entry[0] == keyword)

那只是明显的错误,事实上,你发布的代码是语法错误。方括号是使它成为列表推导的原因。 - Josiah
我认为如果适当添加方括号,这是正确的 - 但我更喜欢原帖末尾的建议。 - happydave
如果你在return语句周围加上括号,它会返回一个生成器对象(方括号会使其与原始代码完全相同),但是生成器仍然包含一个对象,即包含字符串的列表,因此没有任何进展。 - Josiah

0

对之前的不便我深表歉意。 我已经测试了您的代码,如果您查看索引列表,您的值并不统一:

index = [['keyword1', ('url1', 'url2', 'url3')], ['keyword2', ['url4', 'url5']]...]

这里 index[0][1] 是一个元组,index[1][1] 是一个列表。

如果你把 index 里面所有列表的第二个值都变成元组,会发生以下情况:

这是和你的代码一样的代码:

index = [["keyword1", ("url1", "url2", "url3")], ["keyword2", ("url4", "url5")]]
def lookup(index, keyword):
    return [entry[1] for entry in index if entry[0] == keyword]

print lookup(index,"keyword1")

这是输出结果:

[('url1', 'url2', 'url3')]

您可以注意到这不是一个列表中的列表,因为现在index[i][1]中的所有值都是元组。

如果您想要此输出:

['url1', 'url2', 'url3']

你需要将那个元组转换成列表,Python 不会自动为你完成这个过程。正如官方文档所描述的那样,列表推导式总是返回一个列表,这就是为什么元组被放在列表中的原因。

http://www.python.org/dev/peps/pep-0202/


原始帖子中有一个错别字,第一个URL列表无意中被封装在()而不是[]中,已经进行了更正。变量index应该是一个列表的列表:index = [[关键词,[url1,url2] ],[关键词2,[url3,url4]],...] - Verbal_Kint
关于您最初的问题,您无法做任何事情。很多Python原语返回列表是出于设计选择。鉴于列表推导式始终如官方文档中所述返回列表,并且由于您的列表索引包含同时具有一个值也是列表的列表,因此列表推导的输出是一个列表内嵌另一个列表。如果您不希望该输出,则需要取列表的第一个元素并像您在原始帖子中提到的那样返回它。 - Ale
Vaughn-Cato已经在一个语句中解决了这个问题,返回了符合我的条件的列表。 - Verbal_Kint

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接