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]
Related
I want to filter a list of lists for duplicates. I consider two lists to be a duplicate of each other when they contain the same elements but not necessarily in the same order. So for example
[['A', 'B', 'C'], ['C', 'B', 'A'], ['D', 'B', 'A']]
should become
[['A', 'B', 'C'], ['D', 'B', 'A']]
since ['C', 'B', 'A'] is a duplicate of ['A', 'B', 'C'].
It does not matter which one of the duplicates gets removed, as long as the final list of lists does not contain any duplicates anymore. And all lists need to keep the order of there elements. So using set() may not be an option.
I found this related questions:
Determine if 2 lists have the same elements, regardless of order? ,
How to efficiently compare two unordered lists (not sets)?
But they only talk about how to compare two lists, not how too efficiently remove duplicates. I'm using python.
using dictionary comprehension
>>> data = [['A', 'B', 'C'], ['C', 'B', 'A'], ['D', 'B', 'A']]
>>> result = {tuple(sorted(i)): i for i in data}.values()
>>> result
dict_values([['C', 'B', 'A'], ['D', 'B', 'A']])
>>> list( result )
[['C', 'B', 'A'], ['D', 'B', 'A']]
You can use frozenset
>>> x = [['A', 'B', 'C'], ['C', 'B', 'A'], ['D', 'B', 'A']]
>>> [list(s) for s in set([frozenset(item) for item in x])]
[['A', 'B', 'D'], ['A', 'B', 'C']]
Or, with map:
>>> [list(s) for s in set(map(frozenset, x))]
[['A', 'B', 'D'], ['A', 'B', 'C']]
If you want to keep the order of elements:
data = [['A', 'B', 'C'], ['C', 'B', 'A'], ['D', 'B', 'A']]
seen = set()
result = []
for obj in data:
if frozenset(obj) not in seen:
result.append(obj)
seen.add(frozenset(obj))
Output:
[['A', 'B', 'C'], ['D', 'B', 'A']]
Do you want to keep the order of elements?
from itertools import groupby
data = [['A', 'B', 'C'], ['C', 'B', 'A'], ['D', 'B', 'A']]
print([k for k, _ in groupby(data, key=sorted)])
Output:
[['A', 'B', 'C'], ['A', 'B', 'D']]
In python you have to remember that you can't change existing data but you can somehow append / update data.
The simplest way is as follows:
dict = [['A', 'B', 'C'], ['C', 'B', 'A'], ['D', 'B', 'A']]
temp = []
for i in dict:
if sorted(i) in temp:
pass
else:
temp.append(i)
print(temp)
cheers, athrv
I have a list called list_of_strings that looks like this:
['a', 'b', 'c', 'a', 'd', 'c', 'e']
I want to split this list by a value (in this case c). I also want to keep c in the resulting split.
So the expected result is:
[['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]]
Any easy way to do this?
You can use more_itertoools+ to accomplish this simply and clearly:
from more_itertools import split_after
lst = ["a", "b", "c", "a", "d", "c", "e"]
list(split_after(lst, lambda x: x == "c"))
# [['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]
Another example, here we split words by simply changing the predicate:
lst = ["ant", "bat", "cat", "asp", "dog", "carp", "eel"]
list(split_after(lst, lambda x: x.startswith("c")))
# [['ant', 'bat', 'cat'], ['asp', 'dog', 'carp'], ['eel']]
+ A third-party library that implements itertools recipes and more. > pip install more_itertools
stuff = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
You can find out the indices with 'c' like this, and add 1 because you'll be splitting after it, not at its index:
indices = [i + 1 for i, x in enumerate(stuff) if x == 'c']
Then extract slices like this:
split_stuff = [stuff[i:j] for i, j in zip([0] + indices, indices + [None])]
The zip gives you a list of tuples analogous to (indices[i], indices[i + 1]), with the concatenated [0] allowing you to extract the first part and [None] extracting the last slice (stuff[i:])
You could try something like the following:
list_of_strings = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
output = [[]]
for x in list_of_strings:
output[-1].append(x)
if x == 'c':
output.append([])
Though it should be noted that this will append an empty list to your output if your input's last element is 'c'
def spliter(value, array):
res = []
while value in array:
index = array.index(value)
res.append(array[:index + 1])
array = array[index + 1:]
if array:
# Append last elements
res.append(array)
return res
a = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
print(spliter('b',a))
# [['a', 'b'], ['c', 'a', 'd', 'c', 'e']]
print(spliter('c',a))
# [['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]
What about this. It should only iterate over the input once and some of that is in the index method, which is executed as native code.
def splitkeep(v, c):
curr = 0
try:
nex = v.index(c)
while True:
yield v[curr: (nex + 1)]
curr = nex + 1
nex += v[curr:].index(c) + 1
except ValueError:
if v[curr:]: yield v[curr:]
print(list(splitkeep( ['a', 'b', 'c', 'a', 'd', 'c', 'e'], 'c')))
result
[['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]
I wasn't sure if you wanted to keep an empty list at the end of the result if the final value was the value you were splitting on. I made an assumption you wouldn't, so I put a condition in excluding the final value if it's empty.
This has the result that the input [] results in only [] when arguably it might result in [[]].
How about this rather playful script:
a = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
b = ''.join(a).split('c') # ['ab', 'ad', 'e']
c = [x + 'c' if i < len(b)-1 else x for i, x in enumerate(b)] # ['abc', 'adc', 'e']
d = [list(x) for x in c if x]
print(d) # [['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]
It can also handle beginnings and endings with a "c"
a = ['c', 'a', 'b', 'c', 'a', 'd', 'c', 'e', 'c']
d -> [['c'], ['a', 'b', 'c'], ['a', 'd', 'c'], ['e', 'c']]
list_of_strings = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
value = 'c'
new_list = []
temp_list = []
for item in list_of_strings:
if item is value:
temp_list.append(item)
new_list.append(temp_list[:])
temp_list.clear()
else:
temp_list.append(item)
if (temp_list):
new_list.append(temp_list)
print(new_list)
You can try using below snippet. Use more_itertools
>>> l = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
>>> from more_itertools import sliced
>>> list(sliced(l,l.index('c')+1))
Output is:
[['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]
seats = 4 # user can choose an even input, I put 4 for this example
rows = 4 # user can choose an even or odd input, I put 4 for this example
seats_in_row_list = [i for i in string.ascii_uppercase[:seats]]
main_seat_list = [seats_in_row_list for i in range(rows)]
The output is:
[['A', 'B', 'C', 'D'], ['A', 'B', 'C', 'D'], ['A', 'B', 'C', 'D'], ['A', 'B', 'C', 'D']]
But when I try to change 'A' to 'X' in the first list all of the lists change:
[['X', 'B', 'C', 'D'], ['X', 'B', 'C', 'D'], ['X', 'B', 'C', 'D'], ['X', 'B', 'C', 'D']]
What I'm looking for is this output:
[['X', 'B', 'C', 'D'], ['A', 'B', 'C', 'D'], ['A', 'B', 'C', 'D'], ['A', 'B', 'C', 'D']]
Use copy method to have a copy of the individual list before assigning
main_seat_list = [seats_in_row_list.copy() for i in range(rows)]
If you aren't using seats_in_row_list for anything other than the construction of main_seat_list, you should just inline the definition. Calling list here would be simpler than using a list comprehension.
seats = 4
rows = 4
main_seat_list = [list(string.ascii_uppercase[:seats]) for i in range(rows)]
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']
I have a list called list_of_strings that looks like this:
['a', 'b', 'c', 'a', 'd', 'c', 'e']
I want to split this list by a value (in this case c). I also want to keep c in the resulting split.
So the expected result is:
[['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]]
Any easy way to do this?
You can use more_itertoools+ to accomplish this simply and clearly:
from more_itertools import split_after
lst = ["a", "b", "c", "a", "d", "c", "e"]
list(split_after(lst, lambda x: x == "c"))
# [['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]
Another example, here we split words by simply changing the predicate:
lst = ["ant", "bat", "cat", "asp", "dog", "carp", "eel"]
list(split_after(lst, lambda x: x.startswith("c")))
# [['ant', 'bat', 'cat'], ['asp', 'dog', 'carp'], ['eel']]
+ A third-party library that implements itertools recipes and more. > pip install more_itertools
stuff = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
You can find out the indices with 'c' like this, and add 1 because you'll be splitting after it, not at its index:
indices = [i + 1 for i, x in enumerate(stuff) if x == 'c']
Then extract slices like this:
split_stuff = [stuff[i:j] for i, j in zip([0] + indices, indices + [None])]
The zip gives you a list of tuples analogous to (indices[i], indices[i + 1]), with the concatenated [0] allowing you to extract the first part and [None] extracting the last slice (stuff[i:])
You could try something like the following:
list_of_strings = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
output = [[]]
for x in list_of_strings:
output[-1].append(x)
if x == 'c':
output.append([])
Though it should be noted that this will append an empty list to your output if your input's last element is 'c'
def spliter(value, array):
res = []
while value in array:
index = array.index(value)
res.append(array[:index + 1])
array = array[index + 1:]
if array:
# Append last elements
res.append(array)
return res
a = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
print(spliter('b',a))
# [['a', 'b'], ['c', 'a', 'd', 'c', 'e']]
print(spliter('c',a))
# [['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]
What about this. It should only iterate over the input once and some of that is in the index method, which is executed as native code.
def splitkeep(v, c):
curr = 0
try:
nex = v.index(c)
while True:
yield v[curr: (nex + 1)]
curr = nex + 1
nex += v[curr:].index(c) + 1
except ValueError:
if v[curr:]: yield v[curr:]
print(list(splitkeep( ['a', 'b', 'c', 'a', 'd', 'c', 'e'], 'c')))
result
[['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]
I wasn't sure if you wanted to keep an empty list at the end of the result if the final value was the value you were splitting on. I made an assumption you wouldn't, so I put a condition in excluding the final value if it's empty.
This has the result that the input [] results in only [] when arguably it might result in [[]].
How about this rather playful script:
a = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
b = ''.join(a).split('c') # ['ab', 'ad', 'e']
c = [x + 'c' if i < len(b)-1 else x for i, x in enumerate(b)] # ['abc', 'adc', 'e']
d = [list(x) for x in c if x]
print(d) # [['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]
It can also handle beginnings and endings with a "c"
a = ['c', 'a', 'b', 'c', 'a', 'd', 'c', 'e', 'c']
d -> [['c'], ['a', 'b', 'c'], ['a', 'd', 'c'], ['e', 'c']]
list_of_strings = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
value = 'c'
new_list = []
temp_list = []
for item in list_of_strings:
if item is value:
temp_list.append(item)
new_list.append(temp_list[:])
temp_list.clear()
else:
temp_list.append(item)
if (temp_list):
new_list.append(temp_list)
print(new_list)
You can try using below snippet. Use more_itertools
>>> l = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
>>> from more_itertools import sliced
>>> list(sliced(l,l.index('c')+1))
Output is:
[['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]