connected components using Breadth first search - python

I need to find the connected components of a graph.
I have a neighbour list of nodes:
neighbour_list = [[4], [2, 5], [1, 3, 8], [2, 14], [0, 9], [1], [10, 12], [13], [2, 14], [4, 10, 15], [6, 9], [17], [6], [7, 19, 20], [3, 8], [9, 21], [22], [11, 18], [17, 19], [13, 18, 26], [13, 26], [15, 27], [16, 23], [22, 24, 28], [23, 25, 29], [24], [19, 20, 30, 31], [21], [23, 29], [24, 28], [26, 31], [26, 30]]
For example node 0 has neighbour 4, node 1 has neighbours 2 and 5 etc...
What I want to find is a list of connected components. Say node 0 has neighbour 4, yet neighbour 4 also is a neighbour of node 9. Node 9 also has number 10 and 15 neighbours. So the list would be something like
[4,10,15....] etc including following neihbours.
the method I am trying to use is breadth first search.
I wrote the following algorithm:
def bfs(neighbour_list, node):
label_list =[]
for sub_neighbour_list in neighbour_list:
label_list.append(node)
queue = [node]
while queue:
u = queue[0]
for sub_neighbour in neighbour_list[u]:
if sub_neighbour not in queue:
label_list[sub_neighbour] = 0
queue.append(sub_neighbour)
queue.pop(0)
print(label_list)
return (label_list)
nothing happens when I run it. What is wrong?
thanks

What about:
neighbour_list = [[4], [2, 5], [1, 3, 8], [2, 14], [0, 9], [1], [10, 12], [13],
[2, 14], [4, 10, 15], [6, 9], [17], [6], [7, 19, 20], [3, 8],
[9, 21], [22], [11, 18], [17, 19], [13, 18, 26], [13, 26],
[15, 27], [16, 23], [22, 24, 28], [23, 25, 29], [24],
[19, 20, 30, 31], [21], [23, 29], [24, 28], [26, 31], [26, 30]]
def bfs(neighbour_list, root):
queue = []
seen = set()
queue.append(root)
seen.add(root)
while queue:
cn = queue.pop(0)
print("Current node: %d" % cn)
for nn in neighbour_list[cn]:
if nn not in seen:
queue.append(nn)
seen.add(nn)
print(" Found %d" % nn)
return seen
print bfs(neighbour_list, 0)
Which outputs:
Current node: 0
Found 4
Current node: 4
Found 9
Current node: 9
Found 10
Found 15
Current node: 10
Found 6
Current node: 15
Found 21
Current node: 6
Found 12
Current node: 21
Found 27
Current node: 12
Current node: 27
set([0, 4, 6, 9, 10, 12, 15, 21, 27])
Note that set isn't ordered. So the result of this function will return all nodes reachable by root, but not in any sort of order of when the algorithm reached it. If you want that, you could easily change seen to be a list.

This generator function will yield all connected components in a graph represented as an adjacency list. It also uses collections.deque for a queue instead of a list for efficient pops from the beginning of the queue.
from collections import deque
def connected_components(graph):
seen = set()
for root in range(len(graph)):
if root not in seen:
seen.add(root)
component = []
queue = deque([root])
while queue:
node = queue.popleft()
component.append(node)
for neighbor in graph[node]:
if neighbor not in seen:
seen.add(neighbor)
queue.append(neighbor)
yield component
Demo:
neighbour_list = [[4], [2, 5], [1, 3, 8], [2, 14], [0, 9], [1], [10, 12], [13],
[2, 14], [4, 10, 15], [6, 9], [17], [6], [7, 19, 20], [3, 8],
[9, 21], [22], [11, 18], [17, 19], [13, 18, 26], [13, 26],
[15, 27], [16, 23], [22, 24, 28], [23, 25, 29], [24],
[19, 20, 30, 31], [21], [23, 29], [24, 28], [26, 31], [26, 30]]
print(list(connected_components(neighbour_list)))
# [[0, 4, 9, 10, 15, 6, 21, 12, 27],
# [1, 2, 5, 3, 8, 14],
# [7, 13, 19, 20, 18, 26, 17, 30, 31, 11],
# [16, 22, 23, 24, 28, 25, 29]]

Related

Python put days from year in a list grouped by weeks

this is my actual code:
saptamani = []
for months in range(1, 12):
luna = calendar.monthcalendar(2020, months)
for i in luna:
prepare = [m for m in i if m > 0]
if [prepare[0] != prepare[-1]]:
new_w = [prepare[0], prepare[-1]]
saptamani.append(new_w)
Now my code print this:
[[1, 5], [6, 12], [13, 19], [20, 26], [27, 31], [1, 2], [3, 9], [10, 16], [17, 23], [24, 29], [1, 1], [2, 8], [9, 15], [16, 22], [23, 29], [30, 31], [1, 5], [6, 12], [13, 19], [20, 26], [27, 30], [1, 3], [4, 10],
[11, 17], [18, 24], [25, 31], [1, 7], [8, 14], [15, 21], [22, 28], [29, 30], [1, 5], [6, 12], [13, 19], [20, 26], [27, 31], [1, 2], [3, 9], [10, 16], [17, 23], [24, 30], [31, 31], [1, 6], [7, 13], [14, 20], [21, 2
7], [28, 30], [1, 4], [5, 11], [12, 18], [19, 25], [26, 31], [1, 1], [2, 8], [9, 15], [16, 22], [23, 29], [30, 30]]
What I wanted to do is to add the month number too, to be like this
[01.01, 05.01], [05.01, 12.01]....
You think something like this perhaps?
saptamani = []
for months in range(1, 12):
luna = calendar.monthcalendar(2020, months)
for i in luna:
prepare = [m for m in i if m > 0]
if [prepare[0] != prepare[-1]]:
new_w = ["{:02d}.{:02d}".format(prepare[0],months), "{:02d}.{:02d}".format(prepare[-1],months)]
saptamani.append(new_w)
This writes saptamani variable like this:
[['01.01', '05.01'], ['06.01', '12.01'], ['13.01', '19.01'], ['20.01', '26.01'], ['27.01', '31.01'], ['01.02', '02.02'], ['03.02', '09.02'], ['10.02', '16.02'], ['17.02', '23.02'], ['24.02', '29.02'], ['01.03', '01.03'], ['02.03', '08.03'], ['09.03', '15.03'], ['16.03', '22.03'], ['23.03', '29.03'], ['30.03', '31.03'], ['01.04', '05.04'], ['06.04', '12.04'], ['13.04', '19.04'], ['20.04', '26.04'], ['27.04', '30.04'], ['01.05', '03.05'], ['04.05', '10.05'], ['11.05', '17.05'], ['18.05', '24.05'], ['25.05', '31.05'], ['01.06', '07.06'], ['08.06', '14.06'], ['15.06', '21.06'], ['22.06', '28.06'], ['29.06', '30.06'], ['01.07', '05.07'], ['06.07', '12.07'], ['13.07', '19.07'], ['20.07', '26.07'], ['27.07', '31.07'], ['01.08', '02.08'], ['03.08', '09.08'], ['10.08', '16.08'], ['17.08', '23.08'], ['24.08', '30.08'], ['31.08', '31.08'], ['01.09', '06.09'], ['07.09', '13.09'], ['14.09', '20.09'], ['21.09', '27.09'], ['28.09', '30.09'], ['01.10', '04.10'], ['05.10', '11.10'], ['12.10', '18.10'], ['19.10', '25.10'], ['26.10', '31.10'], ['01.11', '01.11'], ['02.11', '08.11'], ['09.11', '15.11'], ['16.11', '22.11'], ['23.11', '29.11'], ['30.11', '30.11']]
Your script wrote integer values but for getting something like "01.01" you need string instead.

How to sum elements inside a nested list?

So, I have a list that looks something like this
[[[1, 2], [3, 4], [5, 6]],
[[7, 8], [9, 10], [11, 12]],
[[13, 14], [15, 16], [17, 18]],
[[19, 20], [21, 22], [23, 24]]]
And I want it to look like this
[[3, 7, 11],
[15, 19, 23],
[27, 31, 35],
[39, 43, 27]]
that is 3 = sum([1, 2]), 7 = sum([3, 4]), ....
I have tried nesting for loops but I haven't found anything that got the desired result, does anyone know how I could do this?
This will do the job quite nicely and imo is more readable than list comprehensions.
lists = [[[1, 2], [3, 4], [5, 6]],
[[7, 8], [9, 10], [11, 12]],
[[13, 14], [15, 16], [17, 18]],
[[19, 20], [21, 22], [23, 24]]]
new_lists = []
for nested in lists:
new_ls = []
for ls in nested:
new_ls.append(sum(ls))
new_lists.append(new_ls)
>>> new_lists
[[3, 7, 11], [15, 19, 23], [27, 31, 35], [39, 43, 47]]
You could also use list comprehensions:
[[sum(x) for x in triple] for triple in lists]
In the above list comprehension, triple will be your list of three doubles so the first for loop will be covering these. x will then be each list of doubles, inside of the triple so we are summing it, while keeping it inside the original triple by using this bracket around:
[sum(x) for x in triple]
output:
[[3, 7, 11], [15, 19, 23], [27, 31, 35], [39, 43, 47]]
If you are happy to use a 3rd party library, you can use NumPy and sum along a single dimension:
import numpy as np
A = np.array([[[1, 2], [3, 4], [5, 6]],
[[7, 8], [9, 10], [11, 12]],
[[13, 14], [15, 16], [17, 18]],
[[19, 20], [21, 22], [23, 24]]])
res = A.sum(2)
Result:
array([[ 3, 7, 11],
[15, 19, 23],
[27, 31, 35],
[39, 43, 47]])
See also: What are the advantages of NumPy over regular Python lists?

Python list comprehension for three-dimensional array

I have a three dimensional array in this format:
x = [
[[1,2,3,4,5],[6,7,8,9,10]],
[[11,12,13,14,15],[16,17,18,19,20]],
[[21,22,23,24,25],[26,27,28,29,30]],
[[21,22,23,24,25]]
]
I'd like to split it into two, three dimensional arrays in this format:
y = [
[[1,2,3],[6,7,8]],
[[11,12,13],[16,17,18]],
[[21,22,23],[26,27,28]],
[[21,22,23]]
]
z = [
[[4,5],[9,10]],
[[14,15],[19,20]],
[[24,25],[29,30]],
[[24,25]]
]
I came up with this list comprehension for creating y:
[j[:3] for i in x for j in i]
Which returns this:
[[1, 2, 3], [6, 7, 8], [11, 12, 13], [16, 17, 18], [21, 22, 23], [26, 27, 28], [31, 32, 33]]
But as you'll see, it doesn't maintain the same multi-dimensional shape. Does anyone have any ideas?
You need to iterate one level deeper:
x = [[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]], [[11, 12, 13, 14, 15], [16, 17, 18, 19, 20]], [[21, 22, 23, 24, 25], [26, 27, 28, 29, 30]], [[21, 22, 23, 24, 25]]]
y = [[i[:3] for i in b] for b in x]
z = [[i[-2:] for i in b] for b in x]
Output:
[[[1, 2, 3], [6, 7, 8]], [[11, 12, 13], [16, 17, 18]], [[21, 22, 23], [26, 27, 28]], [[21, 22, 23]]]
[[[4, 5], [9, 10]], [[14, 15], [19, 20]], [[24, 25], [29, 30]], [[24, 25]]]
Move your inner most loop into a nested comprehension so that the inner lists are preserved:
y = [[j[:3] for j in i] for i in x]

local maximum in lists within list

I have an optimization problem of trying to use less variety of products.
For example:
screws = [6,8,16,18,39]
I would like to exchange those 5 screws with 3. So I need to use the strongest so I could select, [8,18,39]. Using any other option will cause a waste—for example, screw 16 is too strong for location of 6, so [16,18,39] is not as good. I would like to write an algorithm that would be useful for a larger number of parts also. So far I tried this:
def split_list(data, n):
from itertools import combinations, chain
for splits in combinations(range(1, len(data)), n-1):
result = []
prev = None
for split in chain(splits, [None]):
result.append(data[prev:split])
prev = split
yield result
new_list = list(split_list(screws, 3))
#print list(split_list(screws, 3))
As a result of running this code I got a list of lists:
[[[6], [8], [16, 18, 39]],
[[6], [8, 16], [18, 39]],
[[6], [8, 16, 18], [39]],
[[6, 8], [16], [18, 39]],
[[6, 8], [16, 18], [39]],
[[6, 8, 16], [18], [39]]]
I would like to find out local maximums from all the list. For example in the first list [[6], [8],[16, 18, 39]], maximum = 6, maximum = 8, maximum = 39, and so on. But I don't know how to. Is there a way to find local maximum of all nested lists? I'm stuck in this moment, could you help me? I would appreciate also help with further progress.
Later on, I would like to check the sum of differences between maximum and other elements in the same list. So, 6-6 = 0, 8-8 = 0, and last 39-16+30-18-39-39 = 35. This will allow me to find out the smallest value from all lists of lists. This will be the most optimal solution. So the final result should be [[6, 8], [16, 18], [39]] and from it I would select [8,18,39].
This is basically my first program after tutorials and online classes, so all help is very welcome.
You have a list of lists of lists so just iterate over the list then get the max of each of the sublists inside the sublists.
l = [[[6], [8], [16, 18, 39]],
[[6], [8, 16], [18, 39]],
[[6], [8, 16, 18], [39]],
[[6, 8], [16], [18, 39]],
[[6, 8], [16, 18], [39]],
[[6, 8, 16], [18], [39]]]
for sub in l: # each sublist in l -> [[6], [8], [16, 18, 39]]etc..
print([max(ele) for ele in sub]) # each sublist inside each sublist -> [6], [8], [16, 18, 39]
[6, 8, 39]
[6, 16, 39]
[6, 18, 39]
[8, 16, 39]
[8, 18, 39]
[16, 18, 39]
So in your code just do the following:
for sub in split_list(screws, 3):
print([max(ele) for ele in sub])
To get the max minus each element you will have a lot of nested loops:
l = [[[6], [8], [16, 18, 39]],
[[6], [8, 16], [18, 39]],
[[6], [8, 16, 18], [39]],
[[6, 8], [16], [18, 39]],
[[6, 8], [16, 18], [39]],
[[6, 8, 16], [18], [39]]]
result = []
for sub in l:
for sub_ele in sub:
mx = max(sub_ele)
result.append([mx]+map(lambda x: mx-x,sub_ele))
[[6, 0], [8, 0], [39, 23, 21, 0], [6, 0], [16, 8, 0], [39, 21, 0], [6, 0], [18, 10, 2, 0], [39, 0], [8, 2, 0], [16, 0], [39, 21, 0], [8, 2, 0], [18, 2, 0], [39, 0], [16, 10, 8, 0], [18, 0], [39, 0]]

Move elements out of sublists into new list

I have a list that holds several sublist, each one of them with a given number of elements inside. I need to move all elements inside all sublists into another list, ie: remove the separation among elements imposed by the sublists.
This is a MWE if what I mean:
a = [[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]], [[17, 18, 19, 20], [21, 22, 23, 24]], [[25, 26, 27, 28], [26, 30, 31, 32], [33, 34, 35, 36]]]
b = []
for elem in a:
for item in elem:
b.append(item)
which results in:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24], [25, 26, 27, 28], [26, 30, 31, 32], [33, 34, 35, 36]]
I'm sure there's a more elegant and simpler way to do this in python.
Use itertools.chain.from_iterable:
>>> from itertools import chain
>>> list(chain.from_iterable(a))
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24], [25, 26, 27, 28], [26, 30, 31, 32], [33, 34, 35, 36]]
Timing comparison:
Try this:
[item for sublist in a for item in sublist]

Categories

Resources