Python - Creating permutations with output array index constraints - python

I want to create all possible permutations for an array in which each element can only occur once, with constraints on the element array index position.
ID = ["A","B","C","D","E","F","G","H","I","J"]
I want to create all possible permutations of the original_array, however the positions of each element are restricted to index positions given by:
ID = ["A","B","C","D","E","F","G","H","I","J"]
Index_Options=[]
for i in range(len(ID)):
List1=[]
distance=3
value = i - distance
for j in range((int(distance)*2)):
if value < 0 or value > len(ID):
print("Disregard") #Outside acceptable distance range
else:
List1.append(value)
value=value+1
Index_Options.append(List1)
print(Index_Options)
#Index_Options gives the possible index positions for each element. ie "A" can occur in only index positions 0,1,2, "B" can occur in only index positions 0,1,2,3 ect.
I'm just struggling on how to then use this information to create all the output permutations.
Any help would be appreciated

You can use a recursive generator function to build the combinations. Instead of generating all possible permutations from ID and then filtering based on Index_Options, it is much more efficient to produce a cartesian product of ID by directly traversing Index_Options:
ID = ["A","B","C","D","E","F","G","H","I","J"]
def combos(d, c = [], s = []):
if not d:
yield c
else:
for i in filter(lambda x:x not in s and x < len(ID), d[0]):
yield from combos(d[1:], c=c+[ID[i]], s=s+[i])
print(list(combos(Index_Options)))
Output (first ten combinations produced):
[['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'], ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'I'], ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'I', 'H', 'J'], ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'I', 'J', 'H'], ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'J', 'H', 'I'], ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'J', 'I', 'H'], ['A', 'B', 'C', 'D', 'E', 'F', 'H', 'G', 'I', 'J'], ['A', 'B', 'C', 'D', 'E', 'F', 'H', 'G', 'J', 'I'], ['A', 'B', 'C', 'D', 'E', 'F', 'H', 'I', 'G', 'J'], ['A', 'B', 'C', 'D', 'E', 'F', 'H', 'I', 'J', 'G']]

You can use itertools.permutations to create all the possible permutations and then create new list with a check if all the letters are in the correct position
permutations = [p for p in itertools.permutations(ID, len(ID)) if all(i in Index_Options[ID.index(x)] for i, x in enumerate(p))]

Related

How to split/slice a list in Python

I saw this code in w3resource:
C = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n']
def list_slice(S, step):
return [S[i::step] for i in range(step)]
print(list_slice(C,3))
Output :[['a', 'd', 'g', 'j', 'm'], ['b', 'e', 'h', 'k', 'n'], ['c', 'f', 'i', 'l']]
I tried it without list comprehension and a function:
letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n']
step = int(input("Step of every element: "))
for i in range(step):
print(letters[i::step])
Output:
['a', 'd', 'g', 'j', 'm']
['b', 'e', 'h', 'k', 'n']
['c', 'f', 'i', 'l']
is it possible to make my output like this [['a', 'd', 'g', 'j', 'm'], ['b', 'e', 'h', 'k', 'n'], ['c', 'f', 'i', 'l']] without using list comprehension and without making another variable with an empty list?
not a list comprehension solution, but since you want an element having certain distance/step in the list to be in the same list, then you can see that those element index share single property altogether which have the same remainder to the step value, using this approach you can save those value for that index remainder in a key-value pair of dict and in result you can take the values which are nonempty.
C = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n']
def func(lis, slic):
res = {i:[] for i in range(len(lis)//slic)}
for i in range(len(lis)):
res[i%slic].append(lis[i])
return [i for i in res.values() if i!=[]]
print(func(C, 3))
# Output :[['a', 'd', 'g', 'j', 'm'], ['b', 'e', 'h', 'k', 'n'], ['c', 'f', 'i', 'l']]

Find the indices at which any element of one list occurs in another, with duplicates

New to Python, coming from MATLAB. My problem is very similar to this post ( Find the indices at which any element of one list occurs in another ), but with some tweaks that I can't quite manage to incorporate (i.e. managing duplicates and missing values).
Following that example, I have two lists, haystack and needles:
haystack = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K']
needles = ['F', 'G', 'H', 'I', 'F', 'K']
However, both haystack and needles are lists of dates. I need to create a list of indices in haystack for each element of needles in haystack such that:
result = [5, 6, 7, nan, 5, 9]
The two big differences between my problem and the posted example are:
1. I have duplicates in needles (haystack doesn't have any duplicates), which near as I can tell means I can't use set()
2. On rare occasion, an element in needles may not be in haystack, in which case I want to insert a nan (or other placeholder)
So far I've got this (which isn't efficient enough for how large haystack and needles are):
import numpy as np
def find_idx(a,func):
return [i for (i,val) in enumerate(a) if func(val)]
haystack = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K']
needles = ['F', 'G', 'H', 'I', 'F', 'K']
result=[]
for x in needles:
try:
idx = find_idx(haystack, lambda y: y==x)
result.append(idx[0])
except:
result.append(np.nan)
As far as I can tell, that code does what I want, but it's not fast enough. More efficient alternatives?
If your arrays are very large it may be worthwhile to make a dictionary to index the haystack:
haystack = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K']
needles = ['F', 'G', 'H', 'I', 'F', 'K']
hayDict = { K:i for i,K in enumerate(haystack) }
result = [ hayDict.get(N,np.nan) for N in needles]
print(result)
# [5, 6, 7, nan, 5, 9]
How about this?
results=[]
haystack = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K']
needles = ['F', 'G', 'H', 'I', 'F', 'K']
for n in needles:
if n in haystack:
results.append(haystack.index(n))
else:
results.append("NaN")
print (results)
or method2:
haystack = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K']
needles = ['F', 'G', 'H', 'I', 'F', 'K']
results=[]
def getInd(n, haystack):
if n in haystack:
return haystack.index(n)
else:
return "NaN"
for n in needles:
results.append(getInd(n, haystack))
print (results)

Python variable assignment changes value

I am a Network Engineer trying to learn Python programming as a job requirement.
I wrote this code below to
# Funtion to chop the first and last item in the list
def chop(t):
t.pop(0) and t.pop(len(t)-1)
return t
When I run the function on the list t and assign it to a variable a. a gets the remainder of the list after the function was executed and a becomes a new list.This works perfect.
>>> t = ['a', 'b', 'c', 'd', 'e' ,'f','g','h','i','j','k','l']
>>> a=chop(t)
>>> a
['b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']
>>>
Later when i try it works well but the value of a also changes to the output of print chop(t) whereas I did not run the variable a through the function chop(t). Can someone explain why does this happen?
>>> print chop(t)
['c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
>>> a
['c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
Regards
Umesh
To save unmodified list t, create copy of it by a = t[:], and test chop on list a
>>> t = ['a', 'b', 'c', 'd', 'e' ,'f','g','h','i','j','k','l']
>>> a=t[:]
>>> a.pop(0)
'a'
>>> a
['b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l']
>>> t
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l']
>>>
When you call chop(t) , t is being passed by reference. So when you do the operation "t.pop(0) and t.pop(len(t)-1)" , it is being done on the original object and not a copy.
Because of the above , the below is true as well
>>> t = ['a', 'b', 'c', 'd', 'e' ,'f','g','h','i','j','k','l']
>>> chop(t)
>>> t
['b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']
>>>
t = ['a', 'b', 'c', 'd', 'e' ,'f','g','h','i','j','k','l']
def chop(t):
t.pop(0) and t.pop(len(t)-1)
return t
a=chop(t)
In python, Assignment never copies data.
By doing a=chop(t) is like Simply storing the reference to the function in a variable.
Hence, every time we call a we get chop() function executed.

NetworkX shuffles nodes order

I'm beginner to programming and I'm new here, so hello!
I'm having a problem with nodes order in networkX.
This code:
letters = []
G = nx.Graph()
for i in range(nodesNum):
letter = ascii_lowercase[i]
letters.append(letter)
print letters
G.add_nodes_from(letters)
print "G.nodes = ", (G.nodes())
returns this:
['a']
['a', 'b']
['a', 'b', 'c']
['a', 'b', 'c', 'd']
['a', 'b', 'c', 'd', 'e']
['a', 'b', 'c', 'd', 'e', 'f']
['a', 'b', 'c', 'd', 'e', 'f', 'g']
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
G.nodes = ['a', 'c', 'b', 'e', 'd', 'g', 'f', 'i', 'h', 'j']
While I would like to have it in normal (alphabetical) order.
Could anyone tell me what am I doing wrong?
The order is important to me, as later I'm asking user to tell me where the edges are.
Thanks in advance!
You can sort the nodes on output like this
print "G.nodes = ", sorted(G.nodes())
or similarly you can sort the edges like
print "G.edges = ", sorted(G.edges())
Aric's solution would do fine if you want to use this for printing only. However if you are going to use adjacent matrix for calculations and you want consistent matrices in different runs, you should do:
letters = []
G = nx.OrderedGraph()
for i in range(10):
letter = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'][i]
letters.append(letter)
print (letters)
G.add_nodes_from(letters)
print ("G.nodes = ", (G.nodes()))
which returns
['a']
['a', 'b']
['a', 'b', 'c']
['a', 'b', 'c', 'd']
['a', 'b', 'c', 'd', 'e']
['a', 'b', 'c', 'd', 'e', 'f']
['a', 'b', 'c', 'd', 'e', 'f', 'g']
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
G.nodes = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']

Python removing items from a list that exist in another list but keeping duplicates that aren't in that intersect

I'm using python to try and remove items that intersection from another list. So below is what I have.
letter = ['a', 'a', 'i', 'd', 'e', 'i', 'a', 'b', 'b', 'c', 'o', 'g', 'a', 'f', 'f', 'i', 'g', 'i' ]
cons = ['b','c','d', 'f', 'g']
and what I want is to remove any letter in the cons list from the letter list but preserve everything else. So below is what I want to get.
letter = ['a', 'a', 'i', 'e', 'i', 'a', 'o', 'a', i', 'i' ]
Below is what I have tried so far but it's not working.
for i in letter[:]:
if i in cons:
letter.remove(i)
cons.remove(i)
and...
list(set(x) - set(y))
I just want to remove the intersection of the lists and keep the duplicates from the first list that are not in the second list. Everything I've tried so far has removed those duplicates from the first list that I want to keep. Any help is greatly appreciated!
>>> letter = ['a', 'a', 'i', 'd', 'e', 'i', 'a', 'b', 'b', 'c', 'o', 'g', 'a', 'f', 'f', 'i', 'g', 'i' ]
>>> cons = ['b','c','d', 'f', 'g']
>>> [x for x in letter if x not in cons]
['a', 'a', 'i', 'e', 'i', 'a', 'o', 'a', 'i', 'i']
a simple list comprehension will do the trick?
EDIT:
As ShadowRanger said, it would improve performance (mostly for larger data sets than these) to convert cons to a set:
cons = set(cons)
then to go into the list comp. This is better because sets are hashed and makes getting items/checking for items in it way faster
A list comprehension is better, but your original code works if we just remove one line:
>>> letter = ['a', 'a', 'i', 'd', 'e', 'i', 'a', 'b', 'b', 'c', 'o', 'g', 'a', 'f', 'f', 'i', 'g', 'i' ]
>>> cons = ['b','c','d', 'f', 'g']
>>> for i in letter[:]:
... if i in cons:
... letter.remove(i)
...
>>> letter
['a', 'a', 'i', 'e', 'i', 'a', 'o', 'a', 'i', 'i']

Categories