洗牌后的不同结果
Different result upon shuffling a list
我想把一个不完整的图分成独立的、不相连的物体。图的边在列表 edges
中。
代码在打乱边的顺序后给出了不同的结果。这是为什么?
from random import shuffle
edges = [('7', '9'), ('2', '8'), ('4', '10'), ('5', '9'), ('1', '2'), ('1', '6'), ('6', '10')]
bodylist = []
shuffle(edges)
for edge in edges:
#If at least one node of the edge is anywhere in bodylist, append the new nodes to that list.
try:
index = [i for i, body in enumerate(bodylist) if edge[0] in body or edge[1] in body][0]
bodylist[index].append(edge[0])
bodylist[index].append(edge[1])
#If not, make a new list containing the new nodes.
except:
bodylist.append([edge[0], edge[1]])
print([set(x) for x in bodylist])
预期输出:[{'1', '2', '8', '4', '6', '10'}, {'9', '5', '7'}]
一些实际输出:[{'9', '5', '7'}, {'1', '2', '8'}, {'10', '4', '6', '1'}]
[{'9', '7', '5'}, {'6', '2', '1', '8'}, {'6', '10', '4'}]
请注意,预期的输出也会不时出现。 (应该一直如此)
我也会欣赏不同的方法,因为这个可能不是最好的方法。
这是因为你的算法有误。您的算法的问题在于它取决于我们开始创建主体列表时使用的边。为了解释这一点,让我们举一个简单的例子,一个有 4 条边的图 - edges = [('1','2'),('2','3'),('3','4'),('1','4')]
.
第一个案例 -
>>> edges = [('1','2'),('2','3'),('3','4'),('1','4')]
>>> bodylist = []
>>> for edge in edges:
... #If at least one node of the edge is anywhere in bodylist, append the new nodes to that list.
... try:
... index = [i for i, body in enumerate(bodylist) if edge[0] in body or edge[1] in body][0]
... bodylist[index].append(edge[0])
... bodylist[index].append(edge[1])
... #If not, make a new list containing the new nodes.
... except:
... bodylist.append([edge[0], edge[1]])
...
>>> print([set(x) for x in bodylist])
[{'4', '1', '3', '2'}]
你得到一个带有顶点的 body - 1, 2, 3, 4
。为什么?
因为您从 (1,2) 开始将其添加到 body 列表中。然后你拿了 (2,3) ,你看到 2 已经存在于 body 列表中添加的项目中,你再次将它添加到同一个列表中,然后继续并且所有都添加到相同的 body.
现在,让我们以不同的顺序获取相同的边 - edges = [('1','2'),('3','4'),('2','3'),('1','4')]
。结果是 -
>>> edges = [('1','2'),('3','4'),('2','3'),('1','4')]
>>> bodylist = []
>>> .... #same logic
>>> print([set(x) for x in bodylist])
[{'4', '1', '3', '2'}, {'4', '3'}]
正如你这次看到的,你有两个不同的身体(显然它们是错误的)为什么?
你再次从 (1,2) 开始,将其作为 body 添加到 body 列表中,然后你使用 (3,4) ,检查这个,你会看到 none 的顶点已经存在于任何 body 中,因此您将其添加到单独的 body 中。以第三个元素 (2,3) 为例,您会看到它在第一个和第二个 body 中都存在,但您的逻辑是只采用第一个 body 并将元素添加到其中。 (你知道你错在哪里了吗?)
这就是为什么您在打乱列表时得到不同结果的原因,因为顺序对您的逻辑很重要(这是错误的)。
你需要做的是,如果你在多个物体中找到一条边的顶点,你需要将两个物体合并成一个body。
另一个建议,我们不需要将列表添加到 bodylist
中,而是我们可以为每个 body
使用 sets
。
示例解决方案如下所示 -
from random import shuffle
edges = [('7', '9'), ('2', '8'), ('4', '10'), ('5', '9'), ('1', '2'), ('1', '6'), ('6', '10')]
bodylist = []
shuffle(edges)
for edge in edges:
bodies = [body for i, body in enumerate(bodylist) if edge[0] in body or edge[1] in body]
if len(bodies) > 0:
tempset = {edge[0],edge[1]}
for x in bodies:
tempset.update(x)
print('tempset :',tempset)
bodylist.remove(x)
bodylist.append(tempset)
else:
bodylist.append({edge[0],edge[1]})
print([set(x) for x in bodylist])
假设您有三个边 [(1, 2), (3, 4), (2, 3)]
。
这描述了一个连通图。
但是,您的代码将首先检查 (1, 2)
,未发现任何内容,因此将其添加到 bodylist
。
然后,它将查找 (3, 4)
,找不到 3
或 4
,因此将其添加为新列表。
最后它会将(2, 3)
添加到第一个列表但是它不会回来修正它的错误,它不会意识到(3, 4)
属于同一个body。
为了解决这个问题,您可以在每次向主体添加新边时完全遍历剩余的边,以检查是否存在连接:
while edges:
current_edge = edges.pop(0)
body = {current_edge[0], current_edge[1]}
i = 0
while i < len(edges):
if edges[i][0] in body or edges[i][1] in body:
body.add(edges[i][0])
body.add(edges[i][1])
edges.pop(i) # Edge added, no need to check it again
i = 0 # Restart the loop
else:
i += 1
bodylist.append(body)
你要找的是一个叫做connected component的图。
如果您正在寻找高效的算法,您应该看看 this answer。
我想把一个不完整的图分成独立的、不相连的物体。图的边在列表 edges
中。
代码在打乱边的顺序后给出了不同的结果。这是为什么?
from random import shuffle
edges = [('7', '9'), ('2', '8'), ('4', '10'), ('5', '9'), ('1', '2'), ('1', '6'), ('6', '10')]
bodylist = []
shuffle(edges)
for edge in edges:
#If at least one node of the edge is anywhere in bodylist, append the new nodes to that list.
try:
index = [i for i, body in enumerate(bodylist) if edge[0] in body or edge[1] in body][0]
bodylist[index].append(edge[0])
bodylist[index].append(edge[1])
#If not, make a new list containing the new nodes.
except:
bodylist.append([edge[0], edge[1]])
print([set(x) for x in bodylist])
预期输出:[{'1', '2', '8', '4', '6', '10'}, {'9', '5', '7'}]
一些实际输出:[{'9', '5', '7'}, {'1', '2', '8'}, {'10', '4', '6', '1'}]
[{'9', '7', '5'}, {'6', '2', '1', '8'}, {'6', '10', '4'}]
请注意,预期的输出也会不时出现。 (应该一直如此)
我也会欣赏不同的方法,因为这个可能不是最好的方法。
这是因为你的算法有误。您的算法的问题在于它取决于我们开始创建主体列表时使用的边。为了解释这一点,让我们举一个简单的例子,一个有 4 条边的图 - edges = [('1','2'),('2','3'),('3','4'),('1','4')]
.
第一个案例 -
>>> edges = [('1','2'),('2','3'),('3','4'),('1','4')]
>>> bodylist = []
>>> for edge in edges:
... #If at least one node of the edge is anywhere in bodylist, append the new nodes to that list.
... try:
... index = [i for i, body in enumerate(bodylist) if edge[0] in body or edge[1] in body][0]
... bodylist[index].append(edge[0])
... bodylist[index].append(edge[1])
... #If not, make a new list containing the new nodes.
... except:
... bodylist.append([edge[0], edge[1]])
...
>>> print([set(x) for x in bodylist])
[{'4', '1', '3', '2'}]
你得到一个带有顶点的 body - 1, 2, 3, 4
。为什么?
因为您从 (1,2) 开始将其添加到 body 列表中。然后你拿了 (2,3) ,你看到 2 已经存在于 body 列表中添加的项目中,你再次将它添加到同一个列表中,然后继续并且所有都添加到相同的 body.
现在,让我们以不同的顺序获取相同的边 - edges = [('1','2'),('3','4'),('2','3'),('1','4')]
。结果是 -
>>> edges = [('1','2'),('3','4'),('2','3'),('1','4')]
>>> bodylist = []
>>> .... #same logic
>>> print([set(x) for x in bodylist])
[{'4', '1', '3', '2'}, {'4', '3'}]
正如你这次看到的,你有两个不同的身体(显然它们是错误的)为什么?
你再次从 (1,2) 开始,将其作为 body 添加到 body 列表中,然后你使用 (3,4) ,检查这个,你会看到 none 的顶点已经存在于任何 body 中,因此您将其添加到单独的 body 中。以第三个元素 (2,3) 为例,您会看到它在第一个和第二个 body 中都存在,但您的逻辑是只采用第一个 body 并将元素添加到其中。 (你知道你错在哪里了吗?)
这就是为什么您在打乱列表时得到不同结果的原因,因为顺序对您的逻辑很重要(这是错误的)。
你需要做的是,如果你在多个物体中找到一条边的顶点,你需要将两个物体合并成一个body。
另一个建议,我们不需要将列表添加到 bodylist
中,而是我们可以为每个 body
使用 sets
。
示例解决方案如下所示 -
from random import shuffle
edges = [('7', '9'), ('2', '8'), ('4', '10'), ('5', '9'), ('1', '2'), ('1', '6'), ('6', '10')]
bodylist = []
shuffle(edges)
for edge in edges:
bodies = [body for i, body in enumerate(bodylist) if edge[0] in body or edge[1] in body]
if len(bodies) > 0:
tempset = {edge[0],edge[1]}
for x in bodies:
tempset.update(x)
print('tempset :',tempset)
bodylist.remove(x)
bodylist.append(tempset)
else:
bodylist.append({edge[0],edge[1]})
print([set(x) for x in bodylist])
假设您有三个边 [(1, 2), (3, 4), (2, 3)]
。
这描述了一个连通图。
但是,您的代码将首先检查 (1, 2)
,未发现任何内容,因此将其添加到 bodylist
。
然后,它将查找 (3, 4)
,找不到 3
或 4
,因此将其添加为新列表。
最后它会将(2, 3)
添加到第一个列表但是它不会回来修正它的错误,它不会意识到(3, 4)
属于同一个body。
为了解决这个问题,您可以在每次向主体添加新边时完全遍历剩余的边,以检查是否存在连接:
while edges:
current_edge = edges.pop(0)
body = {current_edge[0], current_edge[1]}
i = 0
while i < len(edges):
if edges[i][0] in body or edges[i][1] in body:
body.add(edges[i][0])
body.add(edges[i][1])
edges.pop(i) # Edge added, no need to check it again
i = 0 # Restart the loop
else:
i += 1
bodylist.append(body)
你要找的是一个叫做connected component的图。
如果您正在寻找高效的算法,您应该看看 this answer。