1

我在 python 中创建了类似查询的搜索,它收集 id 并用类似 whois 数据库的名称解析它们。

所以可以说这是我在 .txt 文件中的数据

["81448068", "jimmy"]
["69711823", "bob"]
["92739493", "kyle, jimmy"]
["96399981", "kyle"]
["40112089", "john, peter"]
["79784393", "matthew, chad"]
["749968","bob, jimmy"]

Id 在左列,在右列是与之关联的名称。我将如何使用某种类型的 while 或 for 循环来搜索该数据,直到所有名称都完全匹配?如果添加了任何数据,此方法应该可以工作,我将向您展示我目前拥有的内容,但是在具有更多名称的较大 txt 文件上,它不起作用

def getNames(name):
    x = []
    f = open("names.txt","r") # that data up there represents names.txt
    for line in f.readlines():
        rid,names = json.loads(line.strip())
        if name in names:
           x += names.split(", ")
    return list(set(x))

我想将这些名称循环回获取名称以获取更多与 x 中返回的名称相关联的名称,但我必须手动添加另一个名称是否存在某种类型的 while 循环直到所有匹配项关联用名字找到了吗?所以做 getNames("jimmy") 会返回,

["bob","jimmy","kyle"] 

然后它会检查所有与 bob 相关联的名字,所有与这些名字相关联的名字,直到不再有相关联,它也会为 jimmy 和 Kyle 这样做。

所以基本上,它会搜索初始名称,在这种情况下让我们使用 jimmy。它返回与“jimmy”关联的名称,然后它会搜索与之关联的每个单独的名称,所以假设它返回,[“bob”,“jimmy”,“kyle”] 然后它会接受 bob,用那个搜索所有名称名称中的名称然后搜索所有这些名称并搜索所有这些名称,直到它执行所有名称然后它会做 jimmy 做同样的事情,然后去 Kyle 做同样的事情。我可以用 for 来做到这一点,但是,我需要添加多个 fors,具体取决于我希望搜索的范围,我将如何让它一段时间,以便它处理数据直到找到所有匹配项。

4

5 回答 5

2

这很有趣。我的基本策略是在文件处理期间修复关联,而不是事后进行搜索。我还没有测试过它,但它应该可以工作,尽管有错别字。

编辑:现在我已经测试过了。

文件names.txt

["81448068", "jimmy"]
["69711823", "bob"]
["92739493", "kyle, jimmy"]
["96399981", "kyle"]
["40112089", "john, kyle"]
["79784393", "matthew, chad"]
["749968"  , "bob, jimmy"]

处理文件:

import json

def process_new_file(filename, associations=None):
    if associations == None:
        associations = {}
    with open(filename, 'r') as f:
        lines = f.readlines()
    for line in lines:
        rid, onames = json.loads(line.strip())
        extras = set([x.strip() for x in onames.split(',')])
        names = set()
        while len(extras) > 0:
            names.update(extras)
            extras = set()
            for name in names:
                if not name in associations:
                    associations[name] = set()
                extras.update(associations[name] - names)
        for name in names:
            associations[name].update(names)
    return associations

if __name__ == '__main__':
    associations = process_new_file('names.txt')
    tmpl = '{:20}: {}'
    for person in associations:
        print tmpl.format(person, ', '.join(associations[person]))

输出:

jimmy               : jimmy, bob, john, kyle
chad                : matthew, chad
kyle                : jimmy, bob, john, kyle
matthew             : matthew, chad
bob                 : jimmy, bob, john, kyle
john                : jimmy, bob, john, kyle
于 2013-10-08T23:27:07.550 回答
1

好的,这就是我的做法:(代码也可以在这里作为要点:https ://gist.github.com/ychaouche/6894532 )

data = [
    ["81448068", "jimmy"],
    ["69711823", "bob"],
    ["92739493", "kyle, jimmy"],
    ["96399981", "kyle"],
    ["40112089", "john, kyle"],
    ["79784393", "matthew, chad"],
    ["749968"  , "bob, jimmy"],
]

class MetaPerson(type):
    _names_cache_ = {}
    def __call__(cls,name):
        return MetaPerson._names_cache_.setdefault(name,type.__call__(cls,name))

class Person(object):
    __metaclass__ = MetaPerson

    def __init__(self,name):
        self.name = name
        self.friends = []

    def __repr__(self):
        return "<Person '%s'>" % self.name

    def add_friend(self,person):
        if not person in self.friends : 
            self.friends.append(person)

        if self not in person.friends:
            person.add_friend(self)

    def get_network(self,depth_limit=-1):
        return [friend for friend in self.get_network_recursive(0,depth_limit,[self])]

    def get_network_recursive(self,actual_depth,depth_limit,network):
        if depth_limit != -1 and actual_depth > depth_limit:
            return

        if all((friend in network for friend in self.friends)):
            return

        for friend in self.friends :
            if not friend in network :
                yield friend
                network.append(friend)
                for friendsfriend in friend.get_network_recursive(actual_depth+1,depth_limit,network):
                    yield friendsfriend

class Population:
    def __init__(self):
        self.members = []

    def find(self,name):
        for member in self.members :
            if member.name == name :
                return member

    def add_member(self,person):
        if not person in self.members : 
            self.members.append(person)

    def __repr__(self):
        return repr(self.members)

def parse(data):
    population = Population()
    for tup in data :
        names   = tup[1].replace(" ","").split(",")
        # will return an existing person if name is already taken
        person1 = Person(names[0])
        # add_member won't add if already present        
        population.add_member(person1)
        if len(names) == 2 :
            # will return an existing person if name is already taken
            person2 = Person(names[1])
            # add_member won't add if already present
            population.add_member(person2)
            person2.add_friend(person1)
    return population

def main():
    population = parse(data)
    print "population",population
    kyle = population.find("kyle")
    print "Kyle's network : ",kyle.get_network(1)

def test():    
    antoine = Person("Antoine")
    johny   = Person("Johny")
    patrick = Person("Patrick")
    lisa    = Person("Lisa")

    johny.add_friend(antoine)
    antoine.add_friend(patrick)
    patrick.add_friend(lisa)
    johny.add_friend(lisa)
    print johny.get_network(1)


if __name__ == "__main__" :
    main()

这是输出

chaouche@karabeela ~/CODE/TEST/PYTHON $ python findnames.py
population [<Person 'jimmy'>, <Person 'bob'>, <Person 'kyle'>, <Person 'john'>, <Person 'matthew'>, <Person 'chad'>]
Kyle's network :  [<Person 'jimmy'>, <Person 'bob'>, <Person 'john'>]
chaouche@karabeela ~/CODE/TEST/PYTHON $

如果我将深度更改为 0(仅表示直接朋友),则输出更改为

chaouche@karabeela ~/CODE/TEST/PYTHON $ python findnames.py
population [<Person 'jimmy'>, <Person 'bob'>, <Person 'kyle'>, <Person 'john'>, <Person 'matthew'>, <Person 'chad'>]
Kyle's network :  [<Person 'jimmy'>, <Person 'john'>]
chaouche@karabeela ~/CODE/TEST/PYTHON $
于 2013-10-09T01:07:25.830 回答
1

这是 eval 可能更合适的情况。eval() 基本上说取一串文本并将其视为 python 代码。因此,由于您的输入文件是 python 列表的格式,它的计算结果是一个列表。(请注意,您可以遍历文件的行,如下所示)。

def generateAssociations():
    associations = dict()

    f = open("names.txt","r")
    for line in f:
        line = eval(line)
        id = int(line[0])
        names = line[1].split(',')
        newNames = [name.strip() for name in names]

        for name in newNames:
            if name not in associations:
                associations[name] = lineNames
            else:
                associations[name] = associations[name] + newNames

    for key, value in associations.items():
        associations[key] = set(value)

    pprint.pprint(associations)

在您的示例数据上运行时,它会将其作为输出:

{'bob': {'jimmy', 'bob'},
'chad': {'matthew', 'chad'},
'jimmy': {'kyle', 'jimmy', 'bob'},
'john': {'john', 'peter'},
'kyle': {'jimmy', 'kyle'},
'matthew': {'matthew', 'chad'},
'peter': {'john', 'peter'}}

这是针对第一级朋友的,但应该很容易进一步扩展。

于 2013-10-08T22:30:52.983 回答
1

就解析文件而言,您做得很好。

至于搜索,您可能应该考虑改变处理整个主题的方式。Python 或任何与此相关的语言都适合实现业务逻辑,但在大多数情况下,它在搜索大数据存储方面并不是很好。因此,如果您将有 1000 个名称,Python 会做得不错,但是一旦您开始输入 1,000,000 个名称,脚本就会停止运行。

为了对大数据存储进行有效搜索,这就是数据库的设计目的。所以明智的做法是先将txt文件中的所有数据转储到数据库中,然后随意查询。这将使您拥有最强大的解决方案,并允许您在未来轻松扩展它。如果您当前正在使用 txt 文件,则可能不需要成熟的数据库,因此 sqlite 就足够了。如果您不知道 Sqlite 是单个文件中的完整 SQL 数据库。无需安装,无需配置,只需文件系统上的一个文件即可。Python 有一个优秀的包装器,它为 sqlite 提供了很好的文档,所以如果你决定走这条路,它应该不会很困难。文档可以在这里找到. 直接使用 sqlite 包装器的另一种替代方法是使用 ORM(对象关系包装器),例如SQLAlchemy,但是如果您不熟悉数据库并且由于您对 db 的使用非常简单,我建议您直接使用 sqlite 包装器。

于 2013-10-08T23:19:19.563 回答
0

您可以通过键入以下内容来创建无限循环:

 loop = "loop"
 while loop == "loop":
     ##your code here...

该程序将永远循环 while 函数下方的任何内容。

于 2017-01-23T08:11:48.727 回答