将文件的各个部分解释为节点和边缘

时间:2015-01-25 23:06:06

标签: python python-3.x dictionary tuples nodes

您的程序应使用以下结构输出包含两部分的文件callgraph.txt。这两个部分用空行隔开。

第一部分:节点

每个节点在一行中显示如下:号码,电话号码,姓名,城市,花费的总时间;其中number是从1开始的标识节点的序号。花费的总时间是电话号码发起的呼叫的总秒数。

第二部分:边缘

每条边在一行中显示如下:原点数,目的地数,重量;其中数字原点和目的地是标识文件第一部分中节点的数字。

callgraph.txt文件的示例可能如下所示。请注意,节点按电话号码排序。

2, 7801234567, Ameneh Gholipour Shahraki, Hinton, 198473
7, 7801236789, Stuart Johnson, Saint Albert, 64399
4, 7803214567, Md Toukir Imam, Sherwood Park, 179532
8, 7804321098, Hamman Samuel, Stony Plain, 57909
1, 7804922860, Osmar Zaiane, Edmonton, 250068
5, 7807890123, Elham Ahmadi, Devon, 129370
9, 7808765432, Amir Hossein Faghih Dinevari, Beaumont, 62552
6, 7808907654, Weifeng Chen, Spruce Grove, 121726
3, 7809876543, Farrukh Ahmed, Edson, 190211

2, 7, 40425
2, 4, 21618
2, 8, 34186
2, 1, 34291
2, 5, 24286
2, 9, 67786
2, 6, 21983
2, 3, 35614
7, 4, 32851
7, 8, 27293
7, 1, 45367

现在我的问题是:我正在努力弄清楚如何完成第二部分而我只是陷入困境。我的问题是,每个唯一的数字都是一个节点,我为其分配一个数字,范围从1到有多少个唯一数字。我想要的是,当一个号码调用另一个号码时,它将打印出两个节点,然后还说明他们之间的谈话时间和每个号码都这样做。任何建议表示赞赏。

这是我到目前为止的代码,它回答了第一部分。

customers=open('customers.txt','r')
calls=open('calls.txt.','r')
nodes= {}
name={}
city={}
total_spent_time={}
with open("customers.txt") as fp:
    for line in fp:
        number = line.split(";")[0]
        if number not in nodes:
            nodes[number] = len(nodes) + 1
        rows=line.split(";")
        name[rows[0]]=rows[1]
        city[rows[0]]=rows[2].strip("\n")
with open("calls.txt") as fp2:    
    for lines in fp2:
        rows2=lines.split(";")
        if rows2[1] not in total_spent_time:
            total_spent_time[rows2[1]]=int(rows2[3])
        elif rows2[1]  in total_spent_time:
            total_spent_time[rows2[1]]+=int(rows2[3])
    print(total_spent_time)

链接到calls.txt文件:http://pastebin.com/RSMnXDtq

链接到customers.txt文件:http://pastebin.com/xMx15nCS

2 个答案:

答案 0 :(得分:1)

这个问题很复杂,需要在编码之前制定计划。首先,电话号码到序列号的映射只是一个外围的麻烦。它可以在输入或输出上完成。在开发求和问题的解决方案时,请忘记序列号。

我假设calls.txt的行由" src dst secs"组成。问题是计算每个(src,dst)对的小计,然后计算每个src的总计。标准数据库报告方法是通过src和dst对调用进行排序,然后为每个src,dst对计算和打印小计,其中src的行后跟src的total。问题始发者通过要求在它们所基于的小计之前打印所有总计来投掷曲线球。因此,您首先计算没有小计的总计。

这里可以使用排序和扫描方法保存小计以便以后打印。尝试这个并不是一个坏主意。但是我们可以通过使用dict将每个src映射到一个dict来跳过排序,将每个dst映射到来自该src的调用的秒小计。

subs = {}
with open(calls.txt) as f:
    for line in f:
        src, dst, sec = line.split()
        sub = subs.get(src, {})
        sub.get(dst, 0) += 1

使用.get(key,default_value)比使用的条件语句容易得多。或者subs可以预先加载(number,{})对。当填充子时,它将类似于以下内容(电话号码是您按顺序排列为2,7和4):

{7801234567: {7801236789: 40425,
              7803214567: 21618,
              ...
             },
 7801236789: (7803214567: 32851,
              ...},
 ...
}

编辑:修改并扩展以下内容..

有了这个,很容易计算每个src的总数。如上所述未经测试的以下内容应该有效。

totals = {key: sum(dstdict.values()) for key, dstdict in subs.items()} 

创建另一个dict,将电话号码映射到序列号。如果每个人都打电话并且是潜艇中的钥匙,则以下情况有效。

seqs = {phone: i for i, phone in subs}

否则在阅读电话号码文件时增加或创建。

答案 1 :(得分:0)

使用迭代器it分两步读取文件。 一旦你得到一个空行,停止第一个循环。 这里的iter将指向下一行,允许您在break指令后继续迭代。

另外,我添加了namedtuple类型的用法,它似乎适合你的任务。

from collections import namedtuple

Call = namedtuple('Call', ['number', 'phone_number', 'name', 'city', 'total_time_spent'])

with open('out.txt', 'r') as f:
    it = iter(f)
    calls = []
    for line in it:
        line = line.strip()
        if not line:
            break
        call = Call(*line.split(', '))
        calls.append(call)


    for line in it:
        # code is similar

我想,你可以自己写第二部分)