How to add items into list using recursion? [closed] - python

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
The issue occurred as continuation of my experiments with the graph theory, so as an input I will also add the picture of my graph:
But I also have a description of this graph in several arrays:
First of all, array with all connections:
arrAllConnections = [['F', 'G'], ['G', 'F'], ['G', 'N'], ['N', 'G'], ['N', 'E'], ['E', 'N'], ['E', 'D'], ['D', 'E'], ['D', 'C'], ['C', 'D'], ['C', 'B'], ['B', 'C'], ['B', 'A'], ['A', 'B'], ['A', 'E'], ['E', 'A'], ['B', 'X8'], ['X8', 'B'], ['X8', 'X3'], ['X3', 'X8'], ['X3', 'X2'], ['X2', 'X3'], ['C', 'T'], ['T', 'C'], ['T', 'T1'], ['T1', 'T'], ['T1', 'Y'], ['Y', 'T1'], ['Y', 'L'], ['L', 'Y'],['L', 'P'], ['P', 'L'], ['P', 'Z'], ['Z', 'P'], ['Z', 'Y'], ['Y', 'Z'], ['L', 'K3'], ['K3', 'L'], ['Z', 'K1'], ['K1', 'Z'], ['K1', 'K2'], ['K2', 'K1']]
I thought that it contains some extra information and added such a line:
arrAllConnections = [list(i) for i in set(map(tuple, arrAllConnections))]
Also there are some nodes which I want to connect to the other node groups. Node groups are cycles and here is the list of cycles:
arrWithWhatToConnect = [['A', 'B', 'C', 'D', 'E'], ['Z', 'P', 'L', 'Y']]
Nodes which to connect are mostly nodes outside the cycles, but they may be 'inside' (for example: 'E' node):
arrWhatToConnect = ['F', 'G', 'N', 'X2', 'X3', 'K3', 'K1', 'K2', 'E']
If you look at the image you may notice several things:
X2 is connected to X3, which is connected to X8, but because the latter is not in the list arrWhatToConnect the process must be stopped;
E node is already in the cycle, so the process will be stopped as soon as E will be found in the cycle;
For other nodes, e.g. F a recursion is needed, in brief it should be smth like that: if F not in cycle/arrWithWhatToConnect, but in arrWhatToConnect -> check next node and repeat check for cycle/arrWithWhatToConnect or/|| arrWhatToConnect.
Finally, here is what I am trying to get:
for 'E' node -> ['A', 'B', 'C', 'D', 'E']
for 'F' node -> ['F', 'G', 'N', 'A', 'B', 'C', 'D', 'E']
etc
These are the lists containing the shortest pathes between chosen nodes and cycles.
My code:
arrWhatToConnect = ['F', 'G', 'N', 'X2', 'X3', 'K3', 'K1', 'K2', 'E']
#THERE IS NO X8!!!!!
arrWithWhatToConnect = [['A', 'B', 'C', 'D', 'E'], ['Z', 'P', 'L', 'Y']]
arrAllConnections = [['F', 'G'], ['G', 'F'], ['G', 'N'], ['N', 'G'], ['N', 'E'], ['E', 'N'], ['E', 'D'], ['D', 'E'], ['D', 'C'], ['C', 'D'], ['C', 'B'], ['B', 'C'], ['B', 'A'], ['A', 'B'], ['A', 'E'], ['E', 'A'], ['B', 'X8'], ['X8', 'B'], ['X8', 'X3'], ['X3', 'X8'], ['X3', 'X2'], ['X2', 'X3'], ['C', 'T'], ['T', 'C'], ['T', 'T1'], ['T1', 'T'], ['T1', 'Y'], ['Y', 'T1'], ['Y', 'L'], ['L', 'Y'],['L', 'P'], ['P', 'L'], ['P', 'Z'], ['Z', 'P'], ['Z', 'Y'], ['Y', 'Z'], ['L', 'K3'], ['K3', 'L'], ['Z', 'K1'], ['K1', 'Z'], ['K1', 'K2'], ['K2', 'K1']]
nullFirstConnect = []
#arrAllConnections = (sorted(item for item in arrAllConnections))
arrAllConnections = [list(i) for i in set(map(tuple, arrAllConnections))]
print(arrAllConnections, 'REMOVED?')
def connect(arrWithWhatToConnect, arrWhatToConnect, arrAllConnections, item, olderItems):
arrAllConDel = arrAllConnections
print('CONTENTS OF TRUNCATED ARR CONNECTIONS', arrAllConDel)
arrConnected = []
for cycle in arrWithWhatToConnect:
if item in cycle:
arrConnected.extend(cycle)
arrConnected.extend(olderItems)
print('My item in cycle', item, cycle, arrConnected)
else:
print('Not in cycle', item)
print('GOING TO CHECK ELSEWHERE!')
olderItems.extend(item)
olderItems.extend(olderItems)
for connection in arrAllConnections:
item1 = connection[0]
item2 = connection[1]
if item in connection:
if item == item1:
print('connection is', connection, 'item', item, 'item1', item1, 'item2', item2)
if item2 in arrWhatToConnect:
del arrAllConDel[arrAllConnections.index(connection)]
connect(arrWithWhatToConnect, arrWhatToConnect, arrAllConDel, item2, olderItems)
elif item == item2:
if item1 in arrWhatToConnect:
del arrAllConDel[arrAllConnections.index(connection)]
connect(arrWithWhatToConnect, arrWhatToConnect, arrAllConDel, item1, olderItems)
return arrConnected
for item in arrWhatToConnect:
print(item)
print(connect(arrWithWhatToConnect, arrWhatToConnect, arrAllConnections, item, nullFirstConnect))
It is my first attempt to write any recursion (or if I don't remember it is a realised attempt to write recursion ;)). Everything seems to be more or less clear and even working. But there are not enough return statements, which has an impact on memory. As well as it seems that I should add visitedNodes array. If you can show me how to improve my code please do it. Thanks. Preferably in python without any modules such as nx etc, I would like to understand what is going on inside.

Related

How to remove all duplicates in a 3D Array in Phyton?

So i have an array like this one:
[[['A'], ['C']], [['B', 'E'], ['G']], [['C', 'D'], ['E', 'F']], [['C', 'D'], ['F', 'E']], [['D', 'C'], ['E', 'F']], [['D', 'C'], ['F', 'E']], [['E', 'B'], ['G']], [['F'], ['H']]]
Now i want to remove all the duplicates in the array while different sequences dont matter so CD is the same as DC so the result should look like this:
[[['A'], ['C']], [['B', 'E'], ['G']], [['C', 'D'], ['E', 'F']],[['F'], ['H']]]
How should i do this i thought about three for loops, but is there a simple way to do this? can someone help?
Here's one way to do this:
arr = [[['A'], ['C']], [['B', 'E'], ['G']], [['C', 'D'], ['E', 'F']], [['C', 'D'], ['F', 'E']], [['D', 'C'], ['E', 'F']], [['D', 'C'], ['F', 'E']], [['E', 'B'], ['G']], [['F'], ['H']]]
seen = set()
for a1 in arr:
for i in range(len(a1))[::-1]:
a2 = tuple(sorted(a1[i]))
if a2 in seen:
a1.pop(i)
else:
seen.add(a2)
arr = [*filter(lambda x:x,arr)]
print(arr)
Result:
[[['A'], ['C']], [['B', 'E'], ['G']], [['C', 'D'], ['E', 'F']], [['F'], ['H']]]

Python : Get unique combinations from three seperate lists appended to a single list?

I have three lists with values,
first_lst = ['a','b','c','d']
second_lst = ['i','j','k']
third_lst = ['x','y']
I'm trying to get unique combinations for all three lists append to a list.
Resultant Output:
output = [['a','j','y'],['d','k','x'],............['d','k','y']]
itertools.product from the standard library does that:
import itertools
output = [list(item) for item in itertools.product(first_lst, second_lst, third_lst)]
Ok, if I understand this correctly, you want the lists to turn into a list of all combinations between the lists, like so: [1, 2] and [3, 4] turn into [[1, 3], [1, 4], [2, 3], [2, 4]]
one way to do this is just a loop of loops:
first_lst = ['a', 'b', 'c', 'd']
second_lst = ['i', 'j', 'k']
third_lst = ['x', 'y']
new_lst = []
for x in first_lst:
for y in second_lst:
for z in third_lst:
new_lst.append([x, y, z])
print(new_lst)
prints:
[['a', 'i', 'x'], ['a', 'i', 'y'], ['a', 'j', 'x'], ['a', 'j', 'y'], ['a', 'k', 'x'], ['a', 'k', 'y'], ['b', 'i', 'x'], ['b', 'i', 'y'], ['b', 'j', 'x'], ['b', 'j', 'y'], ['b', 'k', 'x'], ['b', 'k', 'y'], ['c', 'i', 'x'], ['c', 'i', 'y'], ['c', 'j', 'x'], ['c', 'j', 'y'], ['c', 'k', 'x'], ['c', 'k', 'y'], ['d', 'i', 'x'], ['d', 'i', 'y'], ['d', 'j', 'x'], ['d', 'j', 'y'], ['d', 'k', 'x'], ['d', 'k', 'y']]
Use zip() function that iterates multiple iterable items like list, tuple, dictionary in python.
first_lst = ['a', 'b', 'c', 'd']
second_lst = ['i', 'j', 'k']
third_lst = ['x', 'y']
output = []
for f, s, t in zip(first_lst, second_lst, third_lst):
output.append([f, s, t])
print(output)

Slice a list such that the result has the 2 elements before and 2 elements after the subject and a constant result length?

Given this sorted array:
>>> x = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l']
I want to slice up this array so that there are always 5 elements. 2 above and 2 below. I went with:
>>> [x[i-2:i+2] for i, v in enumerate(x)]
This results in:
[[], [], ['a', 'b', 'c', 'd'], ['b', 'c', 'd', 'e'], ['c', 'd', 'e', 'f'], ['d', 'e', 'f', 'g'], ['e', 'f', 'g', 'h'], ['f', 'g', 'h', 'i'], ['g', 'h', 'i', 'j'], ['h', 'i', 'j', 'k'], ['i', 'j', 'k', 'l'], ['j', 'k', 'l']]
The problems with this are:
There are 4 elements per group, not 5
Not every group has 2 above and 2 below.
The first and last groups are special cases. I do not want
blanks at the front. What I want to see is ['a', 'b', 'c', 'd', 'e'] as the first group and then ['b', 'c', 'd', 'e', 'f']
as the second group.
I also played around with clamping the slices.
First I defined a clamp function like so:
>>> def clamp(n, smallest, largest): return max(smallest, min(n, largest))
Then, I applied the function like so:
>>> [x[clamp(i-2, 0, i):clamp(i+2, i, len(x))] for i, v in enumerate(x)]
But it didn't really work out so well:
[['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd'], ['b', 'c', 'd', 'e'], ['c', 'd', 'e', 'f'], ['d', 'e', 'f', 'g'], ['e', 'f', 'g', 'h'], ['f', 'g', 'h', 'i'], ['g', 'h', 'i', 'j'], ['h', 'i', 'j', 'k'], ['i', 'j', 'k', 'l'], ['j', 'k', 'l']]
Am I even barking up the right tree?
I found two SO articles about this issue, but they didn't address these edge cases:
Search a list for item(s)and return x number of surrounding items in python
efficient way to find several rows above and below a subset of data
A couple of observations:
you may want to use range(len(x)) instead of enumerate, then you will avoid having to unpack the result.
If anyone need to understand slice notation, this may help
Then, you can filter the list inside the comprehension
x = list('abcdefghijklmno')
[ x[i-2:i+2+1] for i in range(len(x)) if len(x[i-2:i+2+1]) == 5 ]
# [['a', 'b', 'c', 'd', 'e'], ['b', 'c', 'd', 'e', 'f'], ['c', 'd', 'e', 'f', 'g'], ['d', 'e', 'f', 'g', 'h'], ['e', 'f', 'g', 'h', 'i'], ['f', 'g', 'h', 'i', 'j'], ['g', 'h', 'i', 'j', 'k'], ['h', 'i', 'j', 'k', 'l'], ['i', 'j', 'k', 'l', 'm'], ['j', 'k', 'l', '`
# On python 3.8 you can use the walrus operator!!!
[ y for i in range(len(x)) if len(y:=x[i-2:i+2+1]) == 5 ]
# [['a', 'b', 'c', 'd', 'e'], ['b', 'c', 'd', 'e', 'f'], ['c', 'd', 'e', 'f', 'g'], ['d', 'e', 'f', 'g', 'h'], ['e', 'f', 'g', 'h', 'i'], ['f', 'g', 'h', 'i', 'j'], ['g', 'h', 'i', 'j', 'k'], ['h', 'i', 'j', 'k', 'l'], ['i', 'j', 'k', 'l', 'm'], ['j', 'k', 'l', 'm', 'n'], ['k', 'l', 'm', 'n', 'o']]

Merging nested lists with overlap

I have to merge nested lists which have an overlap. I keep thinking that there has to be an intelligent solution using list comprehensions and probably difflib, but I can't figure out how it should work.
My lists look like this:
[['C', 'x', 'F'], ['A', 'D', 'E']]
and
[['x', 'F', 'G', 'x'], ['D', 'E', 'H', 'J']].
They are above another, like rows in a matrix. Therefore, they have overlap (in the form of
[['x', 'F'], ['D', 'E']]).
A merge should yield:
[['C', 'x', 'F', 'G', 'x'], ['A', 'D', 'E', 'H', 'J']].
How can I achieve this?
You can try something like this.
list1 = [['C', 'x', 'F'], ['A', 'D', 'E']]
list2 = [['x', 'F', 'G', 'x'], ['D', 'E', 'H', 'J']]
for x in range(len(list1)):
for element in list2[x]:
if element not in list1[x]:
list1[x].append(element)
print list1[x]
Output:
['C', 'x', 'F', 'G']
['A', 'D', 'E', 'H', 'J']
I hope this helps you.

Combine all elements of n lists in python [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
there are a lot of questions and answers about combining and merging lists in python but I have not found a way to create a full combination of all elements.
If I had a list of lists like the following:
data_small = [ ['a','b','c'], ['d','e','f'] ]
data_big = [ ['a','b','c'], ['d','e','f'], ['u','v','w'], ['x','y','z'] ]
How can I get a list of lists with all combinations?
For data_small this should be:
[ [a,b,c], [d,b,c], [a,b,f], [a,e,c],
[d,e,c], [d,b,f], [a,e,f], [d,e,f], ... ]
This should also work for an arbitrary number of lists of the same length like data_big.
I am pretty sure there is a fancy itertools solution for this, right?
I think I deciphered the question:
def so_called_combs(data):
for sublist in data:
for sbl in data:
if sbl==sublist:
yield sbl
continue
for i in range(len(sublist)):
c = sublist[:]
c[i] = sbl[i]
yield c
This returns the required list, if I understood it correctly:
For every list in the data, every element is replaced (but only one at a time) with the corresponding element (same position) in each of the other lists.
For data_big, this returns:
[['a', 'b', 'c'], ['d', 'b', 'c'], ['a', 'e', 'c'], ['a', 'b', 'f'],
['u', 'b', 'c'], ['a', 'v', 'c'], ['a', 'b', 'w'], ['x', 'b', 'c'],
['a', 'y', 'c'], ['a', 'b', 'z'], ['a', 'e', 'f'], ['d', 'b', 'f'],
['d', 'e', 'c'], ['d', 'e', 'f'], ['u', 'e', 'f'], ['d', 'v', 'f'],
['d', 'e', 'w'], ['x', 'e', 'f'], ['d', 'y', 'f'], ['d', 'e', 'z'],
['a', 'v', 'w'], ['u', 'b', 'w'], ['u', 'v', 'c'], ['d', 'v', 'w'],
['u', 'e', 'w'], ['u', 'v', 'f'], ['u', 'v', 'w'], ['x', 'v', 'w'],
['u', 'y', 'w'], ['u', 'v', 'z'], ['a', 'y', 'z'], ['x', 'b', 'z'],
['x', 'y', 'c'], ['d', 'y', 'z'], ['x', 'e', 'z'], ['x', 'y', 'f'],
['u', 'y', 'z'], ['x', 'v', 'z'], ['x', 'y', 'w'], ['x', 'y', 'z']]
Here is another way to do using itertools permutations and chain function. You also need to check if the indexes line up and are all the same length, and whether there is more than one element being replaced
from itertools import *
data_small = [ ['a','b','c'], ['d','e','f'] ]
data_big = [ ['a','b','c'], ['d','e','f'], ['u','v','w'], ['x','y','z'] ]
def check(data, sub):
check_for_mul_repl = []
for i in data:
if len(i) != len(data[0]):
return False
for j in i:
if j in sub:
if i.index(j) != sub.index(j):
return False
else:
if i not in check_for_mul_repl:
check_for_mul_repl.append(i)
if len(check_for_mul_repl) <= 2:
return True
print [x for x in list(permutations(chain(*data_big), 3)) if check(data_big, x)]
['a', 'b', 'c'], ['a', 'b', 'f'], ['a', 'b', 'w'], ['a', 'b', 'z'],
['a', 'e', 'c'], ['a', 'e', 'f'], ['a', 'v', 'c'], ['a', 'v', 'w'],
['a', 'y', 'c'], ['a', 'y', 'z'], ['d', 'b', 'c'], ['d', 'b', 'f'],
['d', 'e', 'c'], ['d', 'e', 'f'], ['d', 'e', 'w'], ['d', 'e', 'z'],
['d', 'v', 'f'], ['d', 'v', 'w'], ['d', 'y', 'f'], ['d', 'y', 'z'],
['u', 'b', 'c'], ['u', 'b', 'w'], ['u', 'e', 'f'], ['u', 'e', 'w'],
['u', 'v', 'c'], ['u', 'v', 'f'], ['u', 'v', 'w'], ['u', 'v', 'z'],
['u', 'y', 'w'], ['u', 'y', 'z'], ['x', 'b', 'c'], ['x', 'b', 'z'],
['x', 'e', 'f'], ['x', 'e', 'z'], ['x', 'v', 'w'], ['x', 'v', 'z'],
['x', 'y', 'c'], ['x', 'y', 'f'], ['x', 'y', 'w'], ['x', 'y', 'z']
This doesn't care if there is more than one element being replaced
from itertools import permutations, chain
data_small = [ ['a','b','c'], ['d','e','f'] ]
data_big = [ ['a','b','c'], ['d','e','f'], ['u','v','w'], ['x','y','z'] ]
def check(data, sub):
for i in data:
if len(i) != len(data[0]):
return False
for j in i:
if j in sub:
if i.index(j) != sub.index(j):
return False
return True
#If you really want lists just change the first x to list(x)
print [x for x in list(permutations(chain(*data_big), 3)) if check(data_big, x)]
['a', 'b', 'c'], ['a', 'b', 'f'], ['a', 'b', 'w'], 61 more...
The reason I use permutations instead of combinations is because ('d','b','c') is equal to ('c','b','d') in terms of combinations and not in permutations
If you just want combinations then that's a lot easier. You can just do
def check(data) #Check if all sub lists are same length
for i in data:
if len(i) != len(data[0]):
return False
return True
if check(data_small):
print list(combinations(chain(*data_small), 3))
[('a', 'b', 'c'), ('a', 'b', 'd'), ('a', 'b', 'e'), ('a', 'b', 'f'),
('a', 'c', 'd'), ('a', 'c', 'e'), ('a', 'c', 'f'), ('a', 'd', 'e'),
('a', 'd', 'f'), ('a', 'e', 'f'), ('b', 'c', 'd'), ('b', 'c', 'e'),
('b', 'c', 'f'), ('b', 'd', 'e'), ('b', 'd', 'f'), ('b', 'e', 'f'),
('c', 'd', 'e'), ('c', 'd', 'f'), ('c', 'e', 'f'), ('d', 'e', 'f')]
Sorry for being late to the party, but here is the fancy "one--liner" (split over multiple lines for readability) using itertools and the extremely useful new Python 3.5 unpacking generalizations (which, by the way, is a significantly faster and more readable way of converting between iterable types than, say, calling list explicitly) --- and assuming unique elements:
>>> from itertools import permutations, repeat, chain
>>> next([*map(lambda m: [m[i][i] for i in range(a)],
{*permutations((*chain(*map(
repeat, map(tuple, l), repeat(a - 1))),), a)})]
for l in ([['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']],)
for a in (len(l[0]),))
[['g', 'h', 'f'], ['g', 'b', 'i'], ['g', 'b', 'f'],
['d', 'b', 'f'], ['d', 'h', 'f'], ['d', 'h', 'i'],
['a', 'e', 'c'], ['g', 'e', 'i'], ['a', 'h', 'i'],
['a', 'e', 'f'], ['g', 'e', 'c'], ['a', 'b', 'i'],
['g', 'b', 'c'], ['g', 'h', 'c'], ['d', 'h', 'c'],
['d', 'b', 'c'], ['d', 'e', 'c'], ['a', 'b', 'f'],
['d', 'b', 'i'], ['a', 'h', 'c'], ['g', 'e', 'f'],
['a', 'e', 'i'], ['d', 'e', 'i'], ['a', 'h', 'f']]
The use of next on the generator and the last two lines are, of course, just unnecessary exploitations of syntax to put the expression into one line, and I hope people will not use this as an example of good coding practice.
EDIT
I just realised that maybe I should give a short explanation. So, the inner part creates a - 1 copies of each sublist (converted to tuples for hashability and uniqueness testing) and chains them together to allow permutations to do its magic, which is to create all permutations of sublists of a sublists length. These are then converted to a set which gets rid of all duplicates which are bound to occur, and then a map pulls out the ith element of the ith sublist within each unique permutation. Finally, a is the length of the first sublist, since all sublists are assumed to have identical lengths.

Categories

Resources