Can somebody explain what does this 'nx.connected_components()' does? - python-2.7

I have got some code from git and i was trying to understand it, here's a part of it, i didn't understand the second line of this code
G = nx.Graph(network_map) # Graph for the whole network
components = list(nx.connected_components(G))
Whats does this function connected_components do? I went through the documentation and couldn't understand it properly.

nx.connected_components(G) will return "A generator of sets of nodes, one for each component of G". A generator in Python allows iterating over values in a lazy manner (i.e., will generate the next item only when necessary).
The documentation provides the following example:
>>> import networkx as nx
>>> G = nx.path_graph(4)
>>> nx.add_path(G, [10, 11, 12])
>>> [len(c) for c in sorted(nx.connected_components(G), key=len, reverse=True)]
[4, 3]
Let's go through it:
G = nx.path_graph(4) - create the directed graph 0 -> 1 -> 2 -> 3
nx.add_path(G, [10, 11, 12]) - add to G: 10 -> 11 -> 12
So, now G is a graph with 2 connected components.
[len(c) for c in sorted(nx.connected_components(G), key=len, reverse=True)] - list the sizes of all connected components in G from the largest to smallest. The result is [4, 3] since {0, 1, 2, 3} is of size 4 and {10, 11, 12} is of size 3.
So just to recap - the result is a generator (lazy iterator) over all connected components in G, where each connected component is simply a set of nodes.

Related

Return the last k numbers of a list (Python) [duplicate]

I need the last 9 numbers of a list and I'm sure there is a way to do it with slicing, but I can't seem to get it. I can get the first 9 like this:
num_list[0:9]
You can use negative integers with the slicing operator for that. Here's an example using the python CLI interpreter:
>>> a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
>>> a[-9:]
[4, 5, 6, 7, 8, 9, 10, 11, 12]
the important line is a[-9:]
a negative index will count from the end of the list, so:
num_list[-9:]
Slicing
Python slicing is an incredibly fast operation, and it's a handy way to quickly access parts of your data.
Slice notation to get the last nine elements from a list (or any other sequence that supports it, like a string) would look like this:
num_list[-9:]
When I see this, I read the part in the brackets as "9th from the end, to the end." (Actually, I abbreviate it mentally as "-9, on")
Explanation:
The full notation is
sequence[start:stop:step]
But the colon is what tells Python you're giving it a slice and not a regular index. That's why the idiomatic way of copying lists in Python 2 is
list_copy = sequence[:]
And clearing them is with:
del my_list[:]
(Lists get list.copy and list.clear in Python 3.)
Give your slices a descriptive name!
You may find it useful to separate forming the slice from passing it to the list.__getitem__ method (that's what the square brackets do). Even if you're not new to it, it keeps your code more readable so that others that may have to read your code can more readily understand what you're doing.
However, you can't just assign some integers separated by colons to a variable. You need to use the slice object:
last_nine_slice = slice(-9, None)
The second argument, None, is required, so that the first argument is interpreted as the start argument otherwise it would be the stop argument.
You can then pass the slice object to your sequence:
>>> list(range(100))[last_nine_slice]
[91, 92, 93, 94, 95, 96, 97, 98, 99]
islice
islice from the itertools module is another possibly performant way to get this. islice doesn't take negative arguments, so ideally your iterable has a __reversed__ special method - which list does have - so you must first pass your list (or iterable with __reversed__) to reversed.
>>> from itertools import islice
>>> islice(reversed(range(100)), 0, 9)
<itertools.islice object at 0xffeb87fc>
islice allows for lazy evaluation of the data pipeline, so to materialize the data, pass it to a constructor (like list):
>>> list(islice(reversed(range(100)), 0, 9))
[99, 98, 97, 96, 95, 94, 93, 92, 91]
The last 9 elements can be read from left to right using numlist[-9:], or from right to left using numlist[:-10:-1], as you want.
>>> a=range(17)
>>> print a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
>>> print a[-9:]
[8, 9, 10, 11, 12, 13, 14, 15, 16]
>>> print a[:-10:-1]
[16, 15, 14, 13, 12, 11, 10, 9, 8]
Here are several options for getting the "tail" items of an iterable:
Given
n = 9
iterable = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Desired Output
[2, 3, 4, 5, 6, 7, 8, 9, 10]
Code
We get the latter output using any of the following options:
from collections import deque
import itertools
import more_itertools
# A: Slicing
iterable[-n:]
# B: Implement an itertools recipe
def tail(n, iterable):
"""Return an iterator over the last *n* items of *iterable*.
>>> t = tail(3, 'ABCDEFG')
>>> list(t)
['E', 'F', 'G']
"""
return iter(deque(iterable, maxlen=n))
list(tail(n, iterable))
# C: Use an implemented recipe, via more_itertools
list(more_itertools.tail(n, iterable))
# D: islice, via itertools
list(itertools.islice(iterable, len(iterable)-n, None))
# E: Negative islice, via more_itertools
list(more_itertools.islice_extended(iterable, -n, None))
Details
A. Traditional Python slicing is inherent to the language. This option works with sequences such as strings, lists and tuples. However, this kind of slicing does not work on iterators, e.g. iter(iterable).
B. An itertools recipe. It is generalized to work on any iterable and resolves the iterator issue in the last solution. This recipe must be implemented manually as it is not officially included in the itertools module.
C. Many recipes, including the latter tool (B), have been conveniently implemented in third party packages. Installing and importing these these libraries obviates manual implementation. One of these libraries is called more_itertools (install via > pip install more-itertools); see more_itertools.tail.
D. A member of the itertools library. Note, itertools.islice does not support negative slicing.
E. Another tool is implemented in more_itertools that generalizes itertools.islice to support negative slicing; see more_itertools.islice_extended.
Which one do I use?
It depends. In most cases, slicing (option A, as mentioned in other answers) is most simple option as it built into the language and supports most iterable types. For more general iterators, use any of the remaining options. Note, options C and E require installing a third-party library, which some users may find useful.

Python: How to encode a solution for an optimization problem

I am working on an optimization problem and needed to encode the solution to the problem. Below is the piece of code I wrote for this task. Part one of the extracts the corresponding cities assigned to each salesman. In Part two of the code, I want to insert the starting and ending depots (cities) of each of the salesmen. I want this process to be dynamic as the starting/ending depots lists will change as the "num_salesmen" variable changes. The "population_list" will hold members of the population. I have given one example to aid in your assistance of this request.
Please let me know if you need further clarification of my logic in the inserting part.
####____BELOW CODE is being designed encode a solution for a GA_____#
populationSize = 1 (this will be varied)
num_salesmen = 2
population_list = [[4, 2, 3], [0, 1, 0], [1, 0], [1, 0]]
## - where [4, 2, 3] is a list of cities to be visited by salesmen,
## - [0, 1, 0] the list of salesman, and
## - [1, 0], [1, 0] are the lists of starting and ending depots of the
salesman one (0) and salesman two (1) respectively.
for pop in population_list:
##----Part ONE: determine cities assigned to each salesman:
Assigned_cites = [[] for x in range(num_salesmen)]
for i in range(len(pop[1])):
for man in range(num_salesmen):
if pop[1][i] == man:
Assigned_cites[man].append(pop[0][i])
##---- Part TWO: inserting the starting and ending depots:
for s_man in range(num_salesmen):
for s_e_d in range(2,num_salesmen+2):
Assigned_cites[s_man].insert(0,pop[s_e_d][0])
Assigned_cites[s_man].append(pop[s_e_d][1])
###- expected result from Part TWO Should look like below, but I am not getting it:
[[1, 4, 3, 0], [1, 2, 0]]
Thanks in advance for your help.
#your extraction logic need a bit of tweaking
Assigned_cites = [[] for x in range(num_salesmen)]
for i in range(len(population_list[1])):
for man in range(num_salesmen):
if population_list[1][i] == man:
Assigned_cites[man].append(population_list[0][i])
print Assigned_cites
s_man = 0 # no need of an outer for loop for sales man
for s_e_d in range(2,num_salesmen+2):
Assigned_cites[s_man].insert(0,population_list[s_e_d][0])
Assigned_cites[s_man].append(population_list[s_e_d][1])
s_man = s_man + 1
print Assigned_cites

I can't remember the name of this mean/delta based transform

I once saw a transformation (a cousin of RLE, delta encoding, and other number based, 1D lossless transformation meant to help the Huffman compression) which was based on a recursive mean / delta operations.
example:
[3, 5] -> [4, +1]
where
4 = (3+5)/2 # the average value
4 - 1 = 3 = # the delta reconstruction
4 + 1 = 5
And the process was applied recursively... Maybe something like :
[3, 5, 4, 6] -> [4, +1, 5, +1] -> [4, 5, +1, +1] -> [4.5, +0.5, 1, +0] etc.
But I can't remember how, since I lost its name, hence I can't google it. Does it ring a bell to someone ?
It's mid / side encoding. Usually audio compressors use it to increase compression ratio for stereo audio. For example, Monkey's Audio compressor use it as pointed out in its documentation: http://www.monkeysaudio.com/theory.html

Counterbalancing in open sesame

I a writing an inline_script in open sesame (python).
Can anyone tell me what's wrong here? (i think its something very simple, but i can not find it)
when i put the number in List = [1,2,3,4,5,6,7] the first line works, but the second does not work :(
BalanceList1 = range(1:7) + range(13:19) #does not work
if self.get('subject_nr') == "BalanceList1":
#here follows a list of commands
BalanceList2 = list(range(7:13))+list(range(19:25)) #does not work either
elif self.get('subject_nr') == "BalanceList2":
#other commands
In python 2.x you can do the following:
BalanceList1 = range(1,6) + range(13,19)
which will generate 2 lists and add them together in BalanceList1:
[1, 2, 3, 4, 5, 13, 14, 15, 16, 17, 18]
In python 3.x, range doesn't return a list anymore but an iterator (and xrange is gone), you have to explicitly convert to list:
BalanceList1 = list(range(1,6))+list(range(13,19))
A more optimal way to avoid creating too many temporary lists would be:
BalanceList1 = list(range(1,6))
BalanceList1.extend(range(13,19)) # avoids creating the list for 13->18
more optimal than:

To change the node's name to have a unique list python

I have a problem. Should I create a series of graphs with the barabasi_albert_graph function that is in the library called NetworkX in Python; I should bring all nodes of the graph in a list but so that if I have two graphs one with 5 nodes and one with 10 nodes. I would like to have a unique list so made [0,1,2,3,4,5,6,7 , 8,9,10,11,12,13,14]. The first 5 represent those of the first graph and the 10 the others. Instead I find having [0,1,2,3,4,0,1,2,3,4,5,6,7,8,9]. How can I do to have the first list so that for example if I write 11 in G gives me True?
You can change the labels using convert_node_labels_to_integers like this
In [1]: import networkx as nx
In [2]: G = nx.barabasi_albert_graph(10,3)
In [3]: H = nx.convert_node_labels_to_integers(G,first_label=100)
In [4]: G.nodes()
Out[4]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [5]: H.nodes()
Out[5]: [100, 101, 102, 103, 104, 105, 106, 107, 108, 109]