Related
Write List comprehensions to produce the following List pattern:
[[2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8]]
a= [2,3,4,5]
pattern = [ ]
l = [ ]
[pattern.append(i+j) for i in a for j in range(0,4)]
print(pattern)
With this code I could just print the output without putting them in the required pattern. Could someone help me out?
You could do:
a = [2, 3, 4, 5]
pattern = [[ai + j for ai in a] for j in range(0, 4)]
print(pattern)
Output
[[2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8]]
You could cast a range to a list for each element in a:
>>> a = [2, 3, 4, 5]
>>> sub_list_size = 4
>>> pattern = [list(range(x, x + sub_list_size)) for x in a]
>>> pattern
[[2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8]]
You can use itertools to perform rolling window operations.
from itertools import islice, tee
l = [i for i in range(2,10)]
#[2, 3, 4, 5, 6, 7, 8, 9]
def sliding_window(iterable, size):
iterables = tee(iter(iterable), size)
window = zip(*(islice(t, n, None) for n,t in enumerate(iterables)))
yield from window
[i for i in sliding_window(l,4)]
[(2, 3, 4, 5), (3, 4, 5, 6), (4, 5, 6, 7), (5, 6, 7, 8), (6, 7, 8, 9)]
I am currently trying to find all possible sets of a list of numbers where two or more elements in the set can NOT be in the same set.
For example, I have an original list [1, 2, 3, 4, 5, 6] and I have a list of sets [{1,2}, {3,4}], meaning that 1 and 2 can not be in the same set and 3 and 4 can not be in the same set.
Given those two inputs, result of the program should be:
{1, 6, 3, 5}
{1, 6, 4, 5}
{2, 6, 3, 5}
{2, 6, 4, 5}
Order does not matter in the final output.
Edit: I rewrote the implementation (without recursion this time). Now I am getting an error that says that I can't remove something from the list because it is not there...
def schedules(overlaps, complete):
print(complete)
final = complete.copy()
print(final)
for sch in complete:
print(sch)
for over in overlaps:
if (over[0] in sch) and (over[1] in sch):
print("This is an overlap!!!")
final.remove(sch)
return final
Here is the error and output of the above code:
[(1, 2, 3, 4), (1, 2, 3, 5), (1, 2, 3, 6), (1, 2, 4, 5), (1, 2, 4,
6), (1, 2, 5, 6), (1, 3, 4, 5), (1, 3, 4, 6), (1, 3, 5, 6), (1, 4,
5, 6), (2, 3, 4, 5), (2, 3, 4, 6), (2, 3, 5, 6), (2, 4, 5, 6), (3,
4, 5, 6)]
[(1, 2, 3, 4), (1, 2, 3, 5), (1, 2, 3, 6), (1, 2, 4, 5), (1, 2, 4,
6), (1, 2, 5, 6), (1, 3, 4, 5), (1, 3, 4, 6), (1, 3, 5, 6), (1, 4,
5, 6), (2, 3, 4, 5), (2, 3, 4, 6), (2, 3, 5, 6), (2, 4, 5, 6), (3,
4, 5, 6)]
(1, 2, 3, 4)
This is an overlap!!!
This is an overlap!!!
Traceback (most recent call last):
File "schedule.py", line 24, in <module>
result = schedules(overlaps, list(comb))
File "schedule.py", line 19, in schedules
final.remove(sch)
ValueError: list.remove(x): x not in list
Edit: Adding a try, except block around final.remove(sch) removed the error but as noted in the comments below this code will NOT work if there are more then two elements in an overlap set. For example: if overlaps is now [{1,2}, {3,4,5}] the output should be:
{1,6,3}
{1,6,5}
{1,6,4}
{1,6,5}
{2,6,3}
{2,6,5}
{2,6,4}
{2,6,5}
Suggestion:
Start from the list of overlaps and create all permutations using only ever one element for each set.
Add to each of the resulting list the elements from you initial list that do not figure in the overlaps.
In python this basically boils down to 2 lines that work for an arbitrary number of sets of arbitrary length:
from itertools import product
init_list = [1, 2, 3, 4, 5, 6]
overlaps = [{1,2}, {3,4}]
# the 2 lines:
rest = tuple(el for el in init_list if not any(el in ol for ol in overlaps))
[unique + rest for unique in product(*overlaps) if all(u in init_list for u in unique)]
Out[7]: [(1, 3, 5, 6), (1, 4, 5, 6), (2, 3, 5, 6), (2, 4, 5, 6)]
This should work with an arbitrary number of sets of arbitrary length, removing just 1 element of each set at a time from the list. The two versions below produce the same result, with the second using a a single list comprehension, which, while concise, is a bit hard to read.
First it filters the list of sets to get only those that are subsets of the original list. Then it uses itertools.product to derive all combinations using 1 element from each set, then for each result removes those elements from the original list.
from itertools import product
l = [1, 2, 3, 4, 5, 6]
test_sets = [{1, 2}, {3, 4}]
result = []
subsets = [u for t in test_sets for u in combinations(t, 2) if set(u).issubset(set(l))]
for s in set(product(*subsets)) if len(test_sets) > 1 else subsets:
result.append({r for r in l if r not in s})
print(result)
Result
[{2, 4, 5, 6}, {2, 3, 5, 6}, {1, 4, 5, 6}, {1, 3, 5, 6}]
This code works:
def schedules(overlaps, complete):
final = complete.copy()
for sch in complete:
for over in overlaps:
if (over[0] in sch) and (over[1] in sch):
try:
final.remove(sch)
except:
continue
return final
The error in the question above was caused by me trying to remove the first list twice since it had two overlaps in it. I used a try, except block to get past it.
I wonder if there are better or more "pythonic" ways to do this. Let me know if you have any improvements!
This should do the trick:
from itertools import combinations # to fill the rest of the sequence
# define a recursive function
# it begins to fill the sequences with the mutually exclusive sets
# but also tries to skip them
# it tries to construct only valid combinations
# so it should also perform for larger sets of numbers
def create_sequences(start_sequence, to_length, all_numbers, mutual_exclusive_sets, collect_sequences_in=None):
# leave it up to the user if he want's to pass a list
# if not just create one but for recursive calls just
# reuse the list to avoid garbage collection
result= collect_sequences_in if collect_sequences_in is not None else list()
curr_len= len(start_sequence)
if curr_len == to_length:
# well this is just for safety
result.append(start_sequence)
return result
# create a working copy, so we can remove one item
# (one set of elements which are mutually exclusive)
# so we can pass it to the next recursion if needed
# without spoiling anything
mutual_exclusive_sets= list(mutual_exclusive_sets)
if len(mutual_exclusive_sets) > 0:
# there are mutually exclusive sets left, so grab
# one, during this method call we will just work
# with that set, adding 0 or one elements to the
# sequence and leaving the rest up to a subsequent
# call (if adding one element doesn't complete
# the sequence)
mutual_exclusive_set= mutual_exclusive_sets.pop()
for value in mutual_exclusive_set:
if value in start_sequence:
# that may not be (should only happen if mual_exculsive_sets overlap)
return result
# ok so now call the function with the same sequence
# after removing the one set (this is the case in which
# we don't take any value from the set --> in your example
# that wouldn't be necessary since it will not produce
# a complete sequence and skip this anyways ;-)
create_sequences(list(start_sequence), to_length, all_numbers, mutual_exclusive_sets, collect_sequences_in=result)
# now the case that we take exactly one element from the set
# and add it to the sequence
for value in mutual_exclusive_set:
work_sequence= start_sequence + [value]
if len(work_sequence) == to_length:
result.append(work_sequence)
else:
create_sequences(work_sequence, to_length, all_numbers, mutual_exclusive_sets, collect_sequences_in=result)
elif to_length - curr_len <= len(all_numbers):
# no mutual exclusive sets left, so now add from all_numbers
for tup in combinations(all_numbers, to_length - curr_len):
result.append(start_sequence + list(tup))
else:
# we would have to fill the sequence with items of all_numbers
# but there are no sufficient elements, so skip this step and
# leave result as it is (this was a dead-end --> like if we
# chose to skip one of the mutually exclusive sets in your example
# data --> but e.g. if you run the same with to_length=3 it is relevant)
pass
return result
for the following setup:
all_numbers= [1, 2, 3, 4, 5, 6]
mutual_exclusive= [{1, 2}, {3, 4}]
all_numbers_tmp= list(all_numbers)
for me in mutual_exclusive:
for n in me:
all_numbers_tmp.remove(n)
create_sequences([], 4, all_numbers_tmp, mutual_exclusive)
It returns:
Out[27]: [[3, 1, 5, 6], [3, 2, 5, 6], [4, 1, 5, 6], [4, 2, 5, 6]]
Here is a simpler way to have your desired output using combinations from itertools module along with all and any functions:
from itertools import combinations
def get_combs(ranges, forbidden, r):
for comb in combinations(ranges, r):
if not any(all(k in comb for k in elm) for elm in forbidden):
yield set(comb)
ranges = range(1, 7)
forbidden = [{1, 2}, {3, 4}]
r = 4
combs = list(get_combs(ranges, forbidden, r))
print(combs)
Output:
[{1, 3, 5, 6}, {1, 4, 5, 6}, {2, 3, 5, 6}, {2, 4, 5, 6}]
You can use recursion with a generator. This solution first finds all combinations of the desired length, and then filters based on the matching set:
data, d1 = [1, 2, 3, 4, 5, 6], [{1,2}, {3,4}]
l = len([i for b in d1 for i in b])
def _filter(_d):
return all(len(_d&c) < 2 for c in d1)
def combo(d, c = []):
if len(c) == l:
yield c
else:
for i in filter(lambda x:x not in c, d):
yield from combo(d, c+[i])
r = [i for i in combo(data) if _filter(set(i))]
Output:
[[1, 3, 5, 6], [1, 3, 6, 5], [1, 4, 5, 6], [1, 4, 6, 5], [1, 5, 3, 6], [1, 5, 4, 6], [1, 5, 6, 3], [1, 5, 6, 4], [1, 6, 3, 5], [1, 6, 4, 5], [1, 6, 5, 3], [1, 6, 5, 4], [2, 3, 5, 6], [2, 3, 6, 5], [2, 4, 5, 6], [2, 4, 6, 5], [2, 5, 3, 6], [2, 5, 4, 6], [2, 5, 6, 3], [2, 5, 6, 4], [2, 6, 3, 5], [2, 6, 4, 5], [2, 6, 5, 3], [2, 6, 5, 4], [3, 1, 5, 6], [3, 1, 6, 5], [3, 2, 5, 6], [3, 2, 6, 5], [3, 5, 1, 6], [3, 5, 2, 6], [3, 5, 6, 1], [3, 5, 6, 2], [3, 6, 1, 5], [3, 6, 2, 5], [3, 6, 5, 1], [3, 6, 5, 2], [4, 1, 5, 6], [4, 1, 6, 5], [4, 2, 5, 6], [4, 2, 6, 5], [4, 5, 1, 6], [4, 5, 2, 6], [4, 5, 6, 1], [4, 5, 6, 2], [4, 6, 1, 5], [4, 6, 2, 5], [4, 6, 5, 1], [4, 6, 5, 2], [5, 1, 3, 6], [5, 1, 4, 6], [5, 1, 6, 3], [5, 1, 6, 4], [5, 2, 3, 6], [5, 2, 4, 6], [5, 2, 6, 3], [5, 2, 6, 4], [5, 3, 1, 6], [5, 3, 2, 6], [5, 3, 6, 1], [5, 3, 6, 2], [5, 4, 1, 6], [5, 4, 2, 6], [5, 4, 6, 1], [5, 4, 6, 2], [5, 6, 1, 3], [5, 6, 1, 4], [5, 6, 2, 3], [5, 6, 2, 4], [5, 6, 3, 1], [5, 6, 3, 2], [5, 6, 4, 1], [5, 6, 4, 2], [6, 1, 3, 5], [6, 1, 4, 5], [6, 1, 5, 3], [6, 1, 5, 4], [6, 2, 3, 5], [6, 2, 4, 5], [6, 2, 5, 3], [6, 2, 5, 4], [6, 3, 1, 5], [6, 3, 2, 5], [6, 3, 5, 1], [6, 3, 5, 2], [6, 4, 1, 5], [6, 4, 2, 5], [6, 4, 5, 1], [6, 4, 5, 2], [6, 5, 1, 3], [6, 5, 1, 4], [6, 5, 2, 3], [6, 5, 2, 4], [6, 5, 3, 1], [6, 5, 3, 2], [6, 5, 4, 1], [6, 5, 4, 2]]
m = [[5,9,1,8],
[2,4,5,7],
[6,3,3,2],
[1,7,6,3]]
rotated_map = []
for i in range(len(m[0])):
rotated_map.append([x[i] for x in m])
print(rotated_map)
"""
my result = [[5, 2, 6, 1], [9, 4, 3, 7], [1, 5, 3, 6], [8, 7, 2, 3]]
desired result = [[8,7,2,3],
[1,5,3,6],
[9,4,3,7],
[5,2,6,1]]
"""
I am trying to rotate the list by putting all the last elements first from the lists into one list then the second to last element into another and so on until i get to the first element.
Transpose the list with zip, then reverse it with the [::-1] syntax.
>>> m = [[5, 9, 1, 8], [2, 4, 5, 7], [6, 3, 3, 2], [1, 7, 6, 3]]
>>> list(map(list, zip(*m)))[::-1]
>>> [[8, 7, 2, 3], [1, 5, 3, 6], [9, 4, 3, 7], [5, 2, 6, 1]]
edit:
If you want pretty printing, it's probably easiest to use numpy arrays all the way.
>>> import numpy as np
>>>
>>> m = [[5, 9, 1, 8], [2, 4, 5, 7], [6, 3, 3, 2], [1, 7, 6, 3]]
>>> m = np.array(m)
>>> m
>>>
array([[5, 9, 1, 8],
[2, 4, 5, 7],
[6, 3, 3, 2],
[1, 7, 6, 3]])
>>>
>>> m.T[::-1]
>>>
array([[8, 7, 2, 3],
[1, 5, 3, 6],
[9, 4, 3, 7],
[5, 2, 6, 1]])
Note that m and m.T[::-1] share the same data, because m.T[::-1] is just another view of m. If you need to duplicate the data, use
result = m.T[::-1].copy()
You could use zip, unpacking your list of lists with the *, and inversing the result with [::-1]:
m = [[5,9,1,8],
[2,4,5,7],
[6,3,3,2],
[1,7,6,3]]
res = [list(i) for i in zip(*m)][::-1]
>>> res
[[8, 7, 2, 3], [1, 5, 3, 6], [9, 4, 3, 7], [5, 2, 6, 1]]
If numpy is an option, transposing is easier:
import numpy as np
>>> np.transpose(m)[::-1]
array([[8, 7, 2, 3],
[1, 5, 3, 6],
[9, 4, 3, 7],
[5, 2, 6, 1]])
# or:
>>> np.flip(np.transpose(m),0)
array([[8, 7, 2, 3],
[1, 5, 3, 6],
[9, 4, 3, 7],
[5, 2, 6, 1]])
You can use numpy module to do it. It has the property to transpose the array. Check the below code:
import numpy as np
m = [[5,9,1,8],
[2,4,5,7],
[6,3,3,2],
[1,7,6,3]]
arr = np.array(m).transpose()
new_list = []
for i in range(arr.shape[0]-1,-1,-1):
new_list.append(list(arr[i]))
print(new_list)
Output:
[[8, 7, 2, 3], [1, 5, 3, 6], [9, 4, 3, 7], [5, 2, 6, 1]]
If you want to rotate the list clockwise:
list(map(list, zip(*m[::-1])))
Else, for anti-clockwise:
list(map(list, zip(*m)))[::-1]
use the reverse keyword
result = [[5, 2, 6, 1], [9, 4, 3, 7], [1, 5, 3, 6], [8, 7, 2, 3]]
result.reverse()
print(result)
output:
[[8, 7, 2, 3], [1, 5, 3, 6], [9, 4, 3, 7], [5, 2, 6, 1]]
I have a list of lists like this: [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5], [2, 3, 4, 5, 6, 7], [2, 3], [3, 4]]. How can I count the lists which are sublists of more than two lists? For example, here [2, 3] and [3, 4] would be the lists that are sublists of first 3 lists. I want to get rid of them.
This comprehension should do it:
data = [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5], [2, 3, 4, 5, 6, 7], [2, 3], [3, 4]]
solution = [i for i in data if sum([1 for j in data if set(i).issubset(set(j))]) < 3]
set_list = [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5], [2, 3, 4, 5, 6, 7], [2, 3], [3, 4]]
check_list = [[2, 3], [3, 4]]
sublist_to_list = {}
for set in set_list:
for i, sublist in enumerate(check_list):
count = 0
for element in sublist:
if element in set:
count += 1
if count == len(sublist):
if i not in sublist_to_list:
sublist_to_list[i] = [set]
else:
sublist_to_list[i].append(set)
print(sublist_to_list)
Output: {0: [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5], [2, 3, 4, 5, 6, 7], [2, 3]], 1: [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5], [2, 3, 4, 5, 6, 7], [3, 4]]}
which means [2, 3] is subset of [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5], [2, 3, 4, 5, 6, 7], [2, 3]]
and [3, 4] is subset of [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5], [2, 3, 4, 5, 6, 7], [3, 4]]
You can first make a function that gets sub lists of a list:
def sublists(lst):
length = len(lst)
for size in range(1, length + 1):
for start in range(length - size + 1):
yield lst[start:start+size]
Which works as follows:
>>> list(sublists([1, 2, 3, 4, 5]))
[[1], [2], [3], [4], [5], [1, 2], [2, 3], [3, 4], [4, 5], [1, 2, 3], [2, 3, 4], [3, 4, 5], [1, 2, 3, 4], [2, 3, 4, 5], [1, 2, 3, 4, 5]]
Then you can use this to collect all the sublists list indices into a collections.defaultdict:
from collections import defaultdict
lsts = [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5], [2, 3, 4, 5, 6, 7], [2, 3], [3, 4]]
d = defaultdict(list)
for i, lst in enumerate(lsts):
subs = sublists(lst)
while True:
try:
curr = tuple(next(subs))
d[curr].append(i)
except StopIteration:
break
Which will have tuple keys for the sublists, and the list indices as the values.
Then to determine sub lists that occur more than twice in all the lists, you can check if the set of all the indices has a length of more than two:
print([list(k) for k, v in d.items() if len(set(v)) > 2])
Which will give the following sublists:
[[2], [3], [4], [5], [2, 3], [3, 4], [4, 5], [2, 3, 4], [3, 4, 5], [2, 3, 4, 5]]
Similiar questions to this one have been asked before, but none exactly like it an and I'm kind of lost.
If I have 2 sets of lists (or a lists of lists)
listOLists = [[1,2,3],[1,3,2]]
listOLists2 = [[4,5,6],[4,6,5]]
And I want 'merge' the two lists to make
mergedLists = [[1,2,3,4,5,6],[1,3,2,4,5,6],[1,2,3,4,6,5],[1,3,2,4,6,5]]
How would I do this?
list1s=[[1,2,3],[3,2,1],[2,2,2]]
list2s=[[3,3,3],[4,4,4],[5,5,5]]
for indis1 in list1s:
for indis2 in list2s:
print(indis1 + indis2)
try and;
[1, 2, 3, 3, 3, 3]
[1, 2, 3, 4, 4, 4]
[1, 2, 3, 5, 5, 5]
[3, 2, 1, 3, 3, 3]
[3, 2, 1, 4, 4, 4]
[3, 2, 1, 5, 5, 5]
[2, 2, 2, 3, 3, 3]
[2, 2, 2, 4, 4, 4]
[2, 2, 2, 5, 5, 5]
You may use generator to simplify your code, like this:
a = [[1, 2, 3], [1, 3, 2], [2, 1, 3]]
b = [[4, 5, 6], [4, 6, 5], [5, 4, 6]]
c = [i + j for i in a for j in b]
print c
Output:
[[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 6, 5], [1, 2, 3, 5, 4, 6], [1, 3, 2, 4, 5, 6], [1, 3, 2, 4, 6, 5], [1, 3, 2, 5, 4, 6], [2, 1, 3, 4, 5, 6], [2, 1, 3, 4, 6, 5], [2, 1, 3, 5, 4, 6]]
list1 = [[1,2,3],[1,3,2]]
list2 = [[4,5,6],[4,6,5]]
mergedLists = []
for list1_inner in list1:
for list2_inner in list2:
mergedLists.append(list1_inner + list2_inner)
print(mergedLists)
A comparison of methods:
import itertools
import random
l1 = [[random.randint(1,100) for _ in range(100)]for _ in range(100)]
l2 = [[random.randint(1,100) for _ in range(100)]for _ in range(100)]
With itertools:
def itert(l1, l2):
[list(itertools.chain(*x)) for x in itertools.product(l1, l2)]
With for loops:
def forloops(list1, list2):
mergedLists = []
for list1_inner in list1:
for list2_inner in list2:
mergedLists.append(list1_inner + list2_inner)
With a simple Comprehension:
def comp(l1, l2):
[i + j for i in l1 for j in l2]
Speed
%time itert(l1, l2)
Wall time: 99.8 ms
%time comp(l1, l2)
Wall time: 31.3 ms
%time forloops(l1, l2)
Wall time: 46.9 ms