没有嵌套循环的邻接矩阵

时间:2017-10-23 07:57:42

标签: python algorithm

我试图为一组团队成员创建一个邻接矩阵。我已经存储了匹配的详细信息,例如this-

 x={'match1':[1,2,3],'match2':[2,3,4],'match3':[3,4,5]}

此处每个关键词都有一个值列表,其中包含为该场比赛效力的队员。

我试图创建一个邻接矩阵,显示每个团队成员与另一个团队成员的比赛次数

输出应该如下所示

  1 2 3 4 5
1 1 1 1 0 0
2 1 2 2 1 0
3 1 2 3 2 1
4 0 1 2 2 1 
5 0 0 1 1 1
矩阵中的

(i,i)元素是该团队成员所玩的匹配总数。我已经能够使用Counter正确计算值。

from collections import defaultdict, Counter

if __name__=='__main__':
    x = {'match1': [1, 2, 3], 'match2': [2, 3, 4], 'match3': [3, 4, 5]}
    d = defaultdict(list)
    col_count = dict()
    for key, value in x.items():
        for i in value:
            d[i] += value
    for key, value in d.items():
        col_count[key] = Counter(d[key])
    print(col_count)

输出结果为:

{1: Counter({1: 1, 2: 1, 3: 1}), 2: Counter({2: 2, 3: 2, 1: 1, 4: 1}), 3: Counter({3: 3, 2: 2, 4: 2, 1: 1, 5: 1}), 4: Counter({3: 2, 4: 2, 2: 1, 5: 1}), 5: Counter({3: 1, 4: 1, 5: 1})}

鉴于x字典将包含大量键,并且每个键都有一个包含许多元素的列表,我希望避免使用嵌套的for循环。

是否可以将匹配详细信息存储为任何其他数据类型,以便后续计算不需要嵌套循环?

如果字典是最好的方法,是否有可能以其他方式计算字典?

1 个答案:

答案 0 :(得分:1)

在不修改输入和输出格式的情况下,我没有看到如何避免嵌套循环,因为您有按匹配分组的信息,并且您想要通过播放器提取它。你实际可以做的是通过在嵌套循环中创建Counter来避免最后一个循环:

from collections import defaultdict, Counter

if __name__=='__main__':
    x = {'match1': [1, 2, 3], 'match2': [2, 3, 4], 'match3': [3, 4, 5]}
    d = defaultdict(Counter)
    for key, value in x.items():
        for i in value:
            d[i].update(value)
    print(d)

如果可以修改输入,您可以选择以下内容:

from collections import Counter

if __name__=='__main__':
    x = {1: [{1, 2, 3}], 2: [{1, 2, 3}, {2, 3, 4}], 3: [{1, 2, 3}, {2, 3, 4}, {3, 4, 5}], 4: [{2, 3, 4}, {3, 4, 5}], 5: [{3, 4, 5}]}
    d = {player: Counter([p for match in matches for p in match]) for player, matches in x.items()}
    print(d)

在哪里交换嵌套循环以获得dict和列表理解,这应该更有效。可能玩家和比赛不是intlist的{​​{1}} s,所以这可以做得更多一些。例如:

int

from collections import defaultdict, Counter def printMatrix(matrix): print(' '.join([' |'] + list(map(str, matrix.keys())))) print('---+-' + '-'*len(matrix)*2) for row, values in matrix.items(): fmt = ' {row} |' for col in matrix.keys(): fmt += ' {values[' + str(col) + ']}' print(fmt.format(row=row, values=values)) class Entity: def __init__(self): self._id = None @classmethod def register(cls, value): if value in cls.ids: raise ValueError("The provided ID is already in use") cls.ids.add(value) @classmethod def unregister(cls, value): if value is not None: cls.ids.remove(value) @property def id(self): return self._id @id.setter def id(self, value): if value == self.id: return self.register(value) self.unregister(self.id) self._id = value class Player(Entity): ids = set() def __init__(self, pid): super().__init__() self.id = pid self.__matches = set() def __repr__(self): return 'Player<{}>'.format(self.id) @property def matches(self): return set(self.__matches) def inscribe(self, match): if match not in self.__matches: self.__matches.add(match) def delist(self, match): self.__matches.remove(match) class Match(Entity): ids = set() def __init__(self, mid, players): super().__init__() self.id = mid self.__players = set() self.players = players for player in players: player.inscribe(self) def __repr__(self): return 'Match<{}>'.format(self.id) @property def players(self): return set(self.__players) @players.setter def players(self, value): for player in self.__players: player.delist(self) self.__players = set(value) for player in self.__players: player.inscribe(self) if __name__=='__main__': players = [Player(i) for i in range(1, 6)] matches = [Match(i, {players[i-1], players[i], players[i+1]}) for i in range(1, 4)] for player in players: print(player, player.matches) for match in matches: print(match, match.players) d = {player.id: Counter([p.id for match in player.matches for p in match.players]) for player in players} printMatrix(d) 函数只是我将输出打印到屏幕上的帮助。

printMatrix()类避免了EntityPlayer类所需的重复代码,因为它们都具有唯一ID。构造函数创建一个空的Match属性。 _idregister()方法可处理从类属性unregister()添加和删除ID。它还使用getter和setter声明ids属性。子类只需要在构造函数中调用id,并在要强制执行ID唯一性的级别创建super().__init__()类属性,因为idsPlayer正在做。

Match类还具有Player实例只读属性,该属性分别使用matchesinscribe()方法填充和填充。 delist()类具有Match属性及其getter和setter方法。

首先使用两个列表推导创建playersplayers(请记住列表从位置0开始,因此ID为1的matches位于Player)并且打印出相应的关系(他们为参加比赛的球员和球员所打的比赛)。

由于两者都保留对其他类型的引用,因此我们可以从players[0]获取您所请求的dict Counter所需的所有信息。