返回类似作者的列表

时间:2017-12-06 03:22:42

标签: python python-3.x

我正在尝试编写一个函数,它将从键中返回一个键列表(如果这是有意义的话)。例如,这是一本作者和类似作者的字典。

authors = {
    'Ray Bradbury': ['Harlan Ellison', 'Robert Heinlein', 'Isaac Asimov', 'Arthur Clarke'],
    'Harlan Ellison': ['Neil Stephenson', 'Kurt Vonnegut', 'Richard Morgan', 'Douglas Adams'],
    'Kurt Vonnegut': ['Terry Pratchett', 'Tom Robbins', 'Douglas Adams', 'Neil Stephenson', 'Jeff Vandemeer'],
    'Thomas Pynchon': ['Isaac Asimov', 'Jorges Borges', 'Robert Heinlein'],
    'Isaac Asimov': ['Stephen Baxter', 'Ray Bradbury', 'Arthur Clarke', 'Kurt Vonnegut', 'Neil Stephenson'],
    'Douglas Adams': ['Terry Pratchett', 'Chris Moore', 'Kurt Vonnegut']
}

我想出的功能就是:

def get_similar(author_list, author):
    for item in author_list[author]:
        return author_list[author]

仅返回第一个键的项目。我想让它返回所有类似的作者,如下:

get_similar(authors, 'Harlan Ellison')

['Terry Pratchett', 'Tom Robbins', 'Douglas Adams', 'Neil Stephenson', 
 'Jeff Vandemeer','Terry Pratchett', 'Chris Moore', 'Kurt Vonnegut']

在找到给定键(作者)的位置,查看为该键列出的项目,然后返回这些键的项目。在这种情况下,哈伦·埃里森有四位作者 - 尼尔·斯蒂芬森,库尔特·冯内古特,理查德·摩根和道格拉斯·亚当斯。该功能然后查找这些作者,并返回列出的项目 - Kurt Vonnegut返回Terry Pratchett,Tom Robbins,Douglas Adams,Neil Stephenson和Jeff Vandemeer,Douglas Adams返回Terry Pratchett,Chris Moore和Kurt Vonnegut,< / p>

重复是好的,我希望它按字母顺序排列(我假设你最后可以使用sort命令)任何帮助都会非常感激,我很难过!

8 个答案:

答案 0 :(得分:1)

我认为这就是你要找的东西。希望它能让你前进。

authors = {'Ray Bradbury': ['Harlan Ellison', 'Robert Heinlein', 'Isaac Asimov', 'Arthur Clarke'], 'Harlan Ellison': ['Neil Stephenson', 'Kurt Vonnegut', 'Richard Morgan', 'Douglas Adams'], 'Kurt Vonnegut': ['Terry Pratchett', 'Tom Robbins', 'Douglas Adams', 'Neil Stephenson', 'Jeff Vandemeer'], 'Thomas Pynchon': ['Isaac Asimov', 'Jorges Borges', 'Robert Heinlein'], 'Isaac Asimov': ['Stephen Baxter', 'Ray Bradbury', 'Arthur Clarke', 'Kurt  Vonnegut', 'Neil Stephenson'], 'Douglas Adams': ['Terry  Pratchett', 'Chris Moore', 'Kurt Vonnegut']}


def get_similar(authors, author):
    retVal = []
    for k, v in authors.items():
        if k == author:
            for value in v:
                retVal.append(value)
                if value in authors:
                    for v2 in authors[value]:
                       retVal.append(v2)
return sorted(retVal)

get_similar(作者,“Harlan Ellison”)回归 ['克里斯摩尔',  '道格拉斯·亚当斯',  '道格拉斯·亚当斯',  '杰夫范德米尔',  'Kurt Vonnegut',  'Kurt Vonnegut',  'Neil Stephenson',  'Neil Stephenson',  '理查德摩根',  '特里普拉切特',  '特里普拉切特',  '汤姆罗宾斯']

我会留给你弄清楚如何删除重复项。

答案 1 :(得分:1)

你非常接近,但是在找到第一个类似作者的列表后,你应该将你找到的所有作者存储在列表中,然后在for循环结束后将它们全部返回:

def get_similar(author_list, author):
    similar_authors = []
    for item in author_list[author]:
        if item in author_list:
            similar_authors.extend(author_list[item])
    return similar_authors

请注意,我还添加了if语句,以确保item实际上是您词典中的键之一,这样您以后就不会收到错误(例如:&#39; Neil Stephenson&#39;在词典中作为其中一个值的成员,但不是关键词。)

额外信息:

(如果您有兴趣)

另一种选择是将您的功能转换为generator。这样做的好处是不必将所有相似的作者存储在一个列表中,而是yield找到每个作者:

def get_similar2(author_list, author):
    for item in author_list[author]:
        if item in author_list:
            for other_author in author_list[item]:
                yield other_author 

或者,如果您使用的是python 3.3+,可以使用yield from表达式来简化此操作,以获得与get_similar2中相同的代码:

def get_similar3(author_list, author):
    for item in author_list[author]:
        if item in author_list:
            yield from author_list[item]

上面的所有三个函数/生成器都会给你相同的结果(只记得从生成器中获取所有值):

print(get_similar(authors, 'Harlan Ellison'))
['Terry Pratchett', 'Tom Robbins', 'Douglas Adams', 'Neil Stephenson', 'Jeff Vandemeer', 'Terry Pratchett', 'Chris Moore', 'Kurt Vonnegut']

print(list(get_similar2(authors, 'Harlan Ellison')))
['Terry Pratchett', 'Tom Robbins', 'Douglas Adams', 'Neil Stephenson', 'Jeff Vandemeer', 'Terry Pratchett', 'Chris Moore', 'Kurt Vonnegut']

print(list(get_similar3(authors, 'Harlan Ellison')))
['Terry Pratchett', 'Tom Robbins', 'Douglas Adams', 'Neil Stephenson', 'Jeff Vandemeer', 'Terry Pratchett', 'Chris Moore', 'Kurt Vonnegut']

答案 2 :(得分:1)

这是一个使用set和list comprehension的简单解决方案:

def get_similar(author_list, author):
    similar = set(author_list.get(author, []))
    similar.update(*[author_list.get(item, []) for item in similar])
    return sorted(similar)

get_similar(authors, 'Harlan Ellison')

输出:

['Chris Moore', 'Douglas Adams', 'Jeff Vandemeer', 'Kurt Vonnegut',
 'Neil Stephenson', 'Richard Morgan', 'Terry Pratchett', 'Tom Robbins']

答案 3 :(得分:1)

现在你正在做的事情将以for循环的方式运行 - 你基本上只做一次查找并返回,因此你只得到一个条目。你需要做的是做你的查找,找到作者,然后对每个作者进行查找,然后冲洗并重复...最简单的方法是使用一点递归:

def get_similar(authors, author):
    return [a for x in authors.pop(author, []) for a in [x] + get_similar(authors, x)]

get_similar(authors, 'Harlan Ellison')

# ['Neil Stephenson', 'Kurt Vonnegut', 'Terry Pratchett', 'Tom Robbins', 'Douglas Adams',
#  'Terry Pratchett', 'Chris Moore', 'Kurt Vonnegut', 'Neil Stephenson', 'Jeff Vandemeer',
#  'Richard Morgan', 'Douglas Adams']

然后你需要做的就是把它变成一个集合来摆脱重复,然后对它进行排序,或者如果你不介意轻微的性能损失(由于递归),你可以正确地做到这一点在你的功能中:

def get_similar(authors, author):
    return sorted(set([a for x in authors.pop(author, []) for a in [x] + get_similar(authors, x)]))

# ['Chris Moore', 'Douglas Adams', 'Jeff Vandemeer', 'Kurt Vonnegut', 'Neil Stephenson', 'Richard Morgan', 'Terry Pratchett', 'Tom Robbins']

请记住,这会修改输入字典以避免无限递归,因此如果要保持authors字典完整,请将函数调用为get_similar(authors.copy(), author)

答案 4 :(得分:0)

我会使用递归以这种方式找到类似的作者。来发现,想要返回重复项更加不方便(而且更危险,更慢)。

authors = {'Ray Bradbury': ['Harlan Ellison', 'Robert Heinlein', 'Isaac Asimov', 'Arthur Clarke'], 'Harlan Ellison': ['Neil Stephenson', 
           'Kurt Vonnegut', 'Richard Morgan', 'Douglas Adams'], 'Kurt Vonnegut': ['Terry Pratchett', 'Tom Robbins', 'Douglas Adams', 
           'Neil Stephenson', 'Jeff Vandemeer'], 'Thomas Pynchon': ['Isaac Asimov', 'Jorges Borges', 'Robert Heinlein'], 'Isaac Asimov': 
           ['Stephen Baxter', 'Ray Bradbury', 'Arthur Clarke', 'Kurt Vonnegut', 'Neil Stephenson'], 'Douglas Adams': ['Terry Pratchett', 'Chris Moore', 'Kurt Vonnegut']}

def get_similar(author_list, author, currentList=[]):
    for similar in author_list[author]:
        if similar not in currentList:
            currentList.append(similar)
            if similar in authors:
                get_similar(author_list, author, currentList)
    return sorted(currentList)

print(get_similar(authors, "Harlan Ellison"))

返回:

['Douglas Adams', 'Kurt Vonnegut', 'Neil Stephenson', 'Richard Morgan']

答案 5 :(得分:0)

正在发生的事情是函数只接受一个返回来修复它,返回完整行而不重复

def get_similar(author_list, author):
     return sorted(author_list[author])

答案 6 :(得分:0)

一种方法是使用列表推导+ itertools.chain

from itertools import chain

def get_similar(author_list, author):
     return sorted(set(chain(*[v for k,v in authors.items() if k in authors[author]])))

get_similar(authors, 'Harlan Ellison')
#['Chris Moore', 'Douglas Adams', 'Jeff Vandemeer', 'Kurt Vonnegut', 'Neil Stephenson', 'Terry Pratchett', 'Tom Robbins']

答案 7 :(得分:0)

如果它是author值中的一个元素,我不会在输出中包含参数list。您可以使用list comprehension

def get_similar(author_list, author):
    # Lists of similar authors
    similar = [author_list[auth] for auth in author_list[author] if auth in author_list]

    # Merge the lists and sort the authors. Do not include parameter author
    return sorted(auth for sub in similar for auth in sub if auth != author)



authors = {
    'Ray Bradbury': ['Harlan Ellison', 'Robert Heinlein', 'Isaac Asimov', 'Arthur Clarke'],
    'Harlan Ellison': ['Neil Stephenson', 'Kurt Vonnegut', 'Richard Morgan', 'Douglas Adams'],
    'Kurt Vonnegut': ['Terry Pratchett', 'Tom Robbins', 'Douglas Adams', 'Neil Stephenson', 'Jeff Vandemeer'],
    'Thomas Pynchon': ['Isaac Asimov', 'Jorges Borges', 'Robert Heinlein'],
    'Isaac Asimov': ['Stephen Baxter', 'Ray Bradbury', 'Arthur Clarke', 'Kurt Vonnegut', 'Neil Stephenson'],
    'Douglas Adams': ['Terry Pratchett', 'Chris Moore', 'Kurt Vonnegut']
}


>>> get_similar(authors, 'Harlan Ellison')
['Chris Moore', 'Douglas Adams', 'Jeff Vandemeer', 'Kurt Vonnegut', 'Neil Stephenson', 'Terry Pratchett', 'Terry Pratchett', 'Tom Robbins']

>>> get_similar(authors, 'Ray Bradbury')  # There's 'Ray Bradbury' in the values of 'Isaac Asimov'
['Arthur Clarke', 'Douglas Adams', 'Kurt Vonnegut', 'Kurt Vonnegut', 'Neil Stephenson', 'Neil Stephenson', 'Richard Morgan', 'Stephen Baxter']