Create list of adjacent swap permutations - python

I'm looking for a function that would take a list such as [a,b,c,d] and output a list of all the permutations where adjacent indices are swapped i.e. [[b,a,c,d], [a,c,b,d],[a,b,d,c], [d,b,c,a]]
Thanks

Simple way,you can just use a for loop and swap the adjacent items,tmp=l[:] will make a shallow copy,and it won't change original list l.
See more details from What exactly is the difference between shallow copy, deepcopy and normal assignment operation?:
l=['a', 'b', 'c', 'd']
for i in range(len(l)):
tmp=l[:]
tmp[i],tmp[i-1]=tmp[i-1],tmp[i]
print tmp
Result:
['d', 'b', 'c', 'a']
['b', 'a', 'c', 'd']
['a', 'c', 'b', 'd']
['a', 'b', 'd', 'c']

Related

Check which items exist in all sublists [duplicate]

This question already has answers here:
How to find common elements in list of lists?
(7 answers)
Closed 3 years ago.
I would like to collect all the items that exist in every sublist.
Let's say the list of lists looks like this:
list[0] = ['A', 'B', 'C', 'D']
list[1] = ['X', 'B', 'A']
list[2] = ['R', 'C', 'A', 'B', 'X']
'A' and 'B' exist in every sublist and my goal is to save these to another list:
list2 = ['A', 'B']
I've been trying to use list comprehension but I can't figure out how to get it to work the way I want. Any help is greatly appreciated!
If order doesn't matter, you can use set.intersection:
l = [['A', 'B', 'C', 'D'],
['X', 'B', 'A'],
['R', 'C', 'A', 'B', 'X']]
list2 = list(set.intersection(*(set(sl) for sl in l)))
print(list2)
Output:
['A', 'B']
# or ['B', 'A']
Use set intersections, and then convert the result back to a list.
your_list = [
['A', 'B', 'C', 'D'],
['X', 'B', 'A'],
['R', 'C', 'A', 'B', 'X']
]
print(set.intersection(*map(set,your_list)))
If you know the values per list are unique in the first place, and you don't care about order, then you can just use a list of sets in your original code, so this simplifies to:
your_list = [
set(['A', 'B', 'C', 'D']),
set(['X', 'B', 'A']),
set(['R', 'C', 'A', 'B', 'X'])
]
print(set.intersection(*your_list))
Note don't call your own variables list, as it collides with the built-in list type and will get really confusing.
Try this :
>>> list1 = [['A', 'B', 'C', 'D'], ['X', 'B', 'A'], ['R', 'C', 'A', 'B', 'X']]
>>> list2 = list(set(list1[0]).intersection(list1[1]).intersection(list1[2]))
>>> list2
['A', 'B']

slice a list up to a given element

If you have a list my_list = ['a', 'd', 'e', 'c', 'b', 'f'] and you want to construct a sublist, containing all elements up to a given one, for example my_list_up_to_c = ['a', 'd', 'e'], how can this be done in a way that scales easily? Also can this be made faster by using numpy arrays?
The least amount of code would probably be using .index() (note that this searches till the first occurence of the element in said list):
>>> my_list = ['a', 'd', 'e', 'c', 'b', 'f']
>>> my_list
['a', 'd', 'e', 'c', 'b', 'f']
>>> my_list[:my_list.index('c')] # excluding the specified element
['a', 'd', 'e']
>>> my_list[:my_list.index('c')+1] # including the specified element
['a', 'd', 'e', 'c']
The time complexity of the call to .index() is O(n), meaning it will at most iterate once over the list. The list slicing has complexity O(k) (according to this source), meaning it depends on the size of the slice.
So in the worst case the element you look for is at the end of the list, so your search will run till the end of the list (O(n)) and the slice will copy the whole list as well (also O(n)), resulting in a worst case of O(2n) which is still linear complexity.
Use index() to get the first occurrence of a list item. Then use the slice notation to get the desired part of the list.
>>> my_list = ['a', 'd', 'e', 'c', 'b', 'f']
>>> my_list[:my_list.index('c')]
['a', 'd', 'e']
The itertools solution
In[9]: from itertools import takewhile
In[10]: my_list = ['a', 'd', 'e', 'c', 'b', 'f']
In[11]: list(takewhile(lambda x: x != 'c', my_list))
Out[11]: ['a', 'd', 'e']
In Haskell it would be
takeWhile ((/=) 'c') "adecbf"

Combining lists of lists in python

I want to combine list of lists, here is the below sample
mylist = [[['a', 'b'], ['c', 'd']],
[['e', 'f'], ['g', 'h']]]
and the output should be:
output = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
I also tried using itertools, but here is what it returned
>>> combined = list(itertools.chain.from_iterable(mylist))
>>> combined
>>> [['a', 'b'], ['c', 'd'], ['e', 'f'], ['g', 'h']]
How I can achieve this ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
Can anyone highlight whats I'm missing?
The reason why the itertools method didn't work is because what you have isn't a list of lists, but a list of lists of lists. itertools is working properly, its just flattening the list once. Calling the exact same function again with the partially flattened list as an argument will work:
flat = list(itertools.chain.from_iterable(itertools.chain.from_iterable(mylist)))
Or, a simple list comprehension solution:
flat = [item for slist in mylist for sslist in slist for item in sslist]
This basically translates to:
for slist in mylist:
for sslist in slist:
for item in sslist:
flat.append(item)
Keep in mind, both these solutions are only good for dealing with double nesting. If there is a chance you will have to deal with even more nesting, I suggest you look up how to flatten arbitrarily nested lists.
As others have noted, you have two levels here so you need two calls to chain. But you don't actually need the from_iterable call; you can use the * syntax instead:
list(itertools.chain(*itertools.chain(*mylist)))
With numpy.ndarray.flatten():
import numpy as np
mylist = [ [['a', 'b'], ['c', 'd']], [['e', 'f'], ['g', 'h']] ]
a = np.array(mylist).flatten().tolist()
print(a)
The output:
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']

List comprehension with elements appearing twice

Suppose I have list
l = ['a', 'c', 'b']
and what I want is a list where those elements appear twice, one after the other, so
['a', 'a', 'c', 'c', 'b', 'b']
and I want to do this in the most pythonic way possible.
My half solution is doing something like
[[l[i], l[i]] for i in range(len(l))]
which yields
[['a', 'a'], ['c', 'c'], ['b', 'b']]
From here, I'd have to parse (walk) the list to remove the inner lists and obtain a single flat list.
Anyone has a better idea to do this in one go? Obviously things like l * 2 wouldn't help as it gives ['a', 'c', 'b', 'a', 'c', 'b'] and I want the same elements adjacent.
l_2 = [item for item in l for i in range(n)]
Link to origin: Stackoverflow: Repeating elements of a list n times
Using only list comprehension, you can do:
[i for j in my_list for i in [j]*2]
Output:
>>> my_list = ['a', 'c', 'b']
>>> [i for j in my_list for i in [j]*2]
['a', 'a', 'c', 'c', 'b', 'b']
You can zip the list against itself, then flatten it in a list comprehension.
>>> [i for j in zip(l,l) for i in j]
['a', 'a', 'c', 'c', 'b', 'b']
You can use zip function
l = ['a', 'c', 'b']
a = [i for j in zip(l,l) for i in j]
print(a)
Output
['a', 'a', 'c', 'c', 'b', 'b']
More general:
def ntimes(iterable, times=2):
for elt in iterable:
for _ in range(times):
yield elt
Here is a short solution without list comprehension, using the intuitive idea l*2:
sorted(l*2, key=l.index)
#['a', 'a', 'c', 'c', 'b', 'b']
If you like functional approaches, you can do this:
from itertools import chain, tee
l = ['a', 'c', 'b']
n = 2
list(chain.from_iterable(zip(*tee(l, n))))
While this might not perform as fast as the other answers, it can easily be used for arbitrary iterables (especially when they are infite or when you don't know when they end) by omitting list().
(Note that some of the other answers can also be adapted for arbitrary iterables by replacing their list comprehension by a generator expression.)

Python List Column Move

I'm trying to move the second value in a list to the third value in a list for each nested list. I tried the below, but it's not working as expected.
Code
List = [['a','b','c','d'],['a','b','c','d'],['a','b','c','d']]
print(List)
col_out = [List.pop(1) for col in List]
col_in = [List.insert(2,List) for col in col_out]
print(List)
Result
[['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd']]
[['a', 'b', 'c', 'd'], [...], [...]]
Desired Result
[['a', 'c', 'b', 'd'], ['a', 'c', 'b', 'd'], ['a', 'c', 'b', 'd']]
UPDATE
Based upon pynoobs comment, i came up with the following. But i'm still not there. Why is 'c' printing?
Code
List = [['a','b','c','d'],['a','b','c','d'],['a','b','c','d']]
col_out = [col.pop(1) for col in List for i in col]
print(col_out)
Result
['b', 'c', 'b', 'c', 'b', 'c']
[List.insert(2,List) for col in col_out]
^^^^ -- See below.
You are inserting an entire list as an element within the same list. Think recursion!
Also, please refrain from using state-changing expressions in list comprehension. A list comprehension should NOT modify any variables. It is bad manners!
In your case, you'd do:
lists = [['a','b','c','d'],['a','b','c','d'],['a','b','c','d']]
for lst in lists:
lst[1], lst[2] = lst[2], lst[1]
print(lists)
Output:
[['a', 'c', 'b', 'd'], ['a', 'c', 'b', 'd'], ['a', 'c', 'b', 'd']]
You can do it like this
myList = [['a','b','c','d'],['a','b','c','d'],['a','b','c','d']]
myOrder = [0,2,1,3]
myList = [[sublist[i] for i in myOrder] for sublist in myList]

Categories