How to produce this specific list of lists - python

I have a bit of a complicated problem. I'm trying to make a function which takes in a list of 0s and 1s and returns a list of lists. It's easiest if I just show an example
input :
[0,0,0,1,0,1]
output :
[[0,0,0,0,0,0,0],[1,0,0,0,1,0,0],[1,0,0,0,1,0,1],[1,0,0,0,0,0,1],[1,0,0,0,0,0,0]]
Another example
input :
[1,0,1]
output :
[[0,0,0,0],[1,1,0,0],[1,0,0,1],[1,1,0,1],[1,0,0,0]]
I have a solution right now, where I first produce all the the combinations and then filters out the ones that are not allowed. But this demands massive amount of memory so I'm looking for a better solution.
def func(input):
A = list(itertools.product(range(2), repeat=int(len(input)+1)))
# Filters out all the lists which have first element equal to 0
# and 1s anywhere else
A = [item for item in A if not (item[0] == 0 \
and sum(item) >= 1 or item[A.index(item)+1] == 1) ]
# Filter out all lists which has 1s at places the input does not have
A = [item for item in action_space if not \
sum(np.bitwise_and(np.bitwise_xor(item[1:], \
self.adj_mat[node.get_node_nr()]),item[1:])) > 0]
return A

You can get a list of the indices to mutate, then use itertools.product to generate all the possible variations.
from itertools import product
def func(l):
indicies = [i for i, x in enumerate(l, start=1) if x]
prod = product([0, 1], repeat=len(indicies))
yield [0] * (len(l) + 1)
for variation in prod:
temp = [1, *l]
for index, value in zip(indicies, variation):
temp[index] = value
yield temp
print(list(func([0,0,0,1,0,1])))
# [[0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 1, 0, 0], [1, 0, 0, 0, 1, 0, 1]]
print(list(func([1,0,1])))
# [[0, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 1], [1, 1, 0, 0], [1, 1, 0, 1]]

Idea: Get indices. Then take all subsets of indices to generate sublists to add to result
from itertools import chain, combinations
def powerset(iterable):
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
lst = [0,0,0,1,0,1]
indices = [i for i, x in enumerate(lst) if x == 1]
result = [[0] * (len(lst)+1)]
for element in powerset(s):
new_element = [[0] * (len(lst)+1)]
new_element[0][0] = 1
for pos in element:
new_element[0][pos+1] = int(1)
result.extend(new_element)
print(result) # [[0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 1, 0, 0], [1, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 1, 0, 1]]

Use itertools.permutations, and just prepend a 1 to each of them.
from itertools import permutations
def augment(xs):
yield [0] + [0 for _ in xs]
for x in permutations(xs):
yield [1] + list(x)
out = list(augment([1,0,1])
If you'd rather write a single expression rather than a generator function, its just
from itertools import chain, permutations
xs = [1, 0, 1]
out = list(chain([[0] + [0 for _ in xs]], ([1] + list(x) for x in permutations(xs))))

Using itertools.product and a generator:
def get_combinations(lst):
yield [0]*(len(lst)+1)
idxs = [idx for idx, x in enumerate(lst) if x]
for vals in product(*[[0, 1]]*2):
vals_i = iter(vals)
yield [1] + [0 if idx not in idxs else next(vals_i) for idx in range(len(lst))]
Then list(get_combinations([0, 0, 0, 1, 0, 1])) prints
[[0, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 1, 0, 0],
[1, 0, 0, 0, 1, 0, 1]]

Related

Return list with consecutive occurances based on another list

I have a list with the following number:
[0, 0, 0, 0, 1, 1, 0, 0, 1]
What I wanna do is count how many consecutive 1s I have and generate a new list like the following one:
[0, 0, 0, 0, 1, 2, 0, 0, 1]
Is there a way to do it in a more compact way than this method?
lst = [0, 0, 0, 0, 1, 1, 0, 0, 1]
new_lst = []
counter = 0
for i in range(len(lst)):
if (lst[i] == 1): counter+=1
else:counter = 0
new_lst.append(counter)
print(new_lst)
You could take advantage of the walrus operator if you're using python 3.8 or later:
[counter := counter + 1 if v else 0 for v in lst]
or perhaps itertools.accumulate:
[v for v in itertools.accumulate(lst, lambda acc, v:acc + v if v else 0)]
In both case the result is:
[0, 0, 0, 0, 1, 2, 0, 0, 1]
It's not so much compact than the question solution but it's more clear:
l = [0, 0, 0, 0, 1, 1, 0, 0, 1]
s = []
occ = 0
for i in l:
occ = occ+1 if i==1 else 0
s.append(occ)
print(s)
Output:
[0, 0, 0, 0, 1, 2, 0, 0, 1]

How to loop by specific step

I have a nested loop data=
[[1,43,344,546],[2,34,45,565]....[10,1,1,1],
[1,15,111,151],[2,152,28,19]....[10,2,2,2],
[1,21,45,1647],[2,288,65,90]....[10,3,3,3]
.....]
so basically, all the inside lists can be grouped by 10lists with the first element always starting from 1 to 10. taking the every 10th list as a key, so I want to calculate a newlist by subtracting every list's number by the 10th list accordingly, for example
[[1,43-1,344-2,546-3], [2,34-1,45-2,565-3].... [10,1,2,3],
[1,15-21,111-22,151-23],[2,152-21,28-22,19-23]....[10,21,22,23],
[1,21-31,45-32,1647-33],[2,288-31,65-32,90-33]....[10,31,32,33]
.....]
My code seems don't work, can someone plz help with this? thanks
line = 0
while line <= (len(data) - 10):
for i in range(line, line + 10):
temp = data[i]
if temp[0] == 10: #find the every 10 th keys and store them to x, y, z
x = temp[1]
y = temp[2]
z = temp[3]
break
for sublist in data:
sublist[1] = sublist[1] - x# assign new elements to original list data
sublist[2] = sublist[2] - y
sublist[3] = sublist[3] - z
line += 10
return data
This is one way to do what you want
from pprint import pprint
def next_mul(n):
"returns next multiple of 10 greater than n"
return n + (10 - n % 10)
# sample data
data = [[i for i in range(4)] for i in range(20)]
for i in range(len(data)):
if i % 10 == 0:
continue
data[i-1][1:] = [k-l for k,l in zip(data[next_mul(i)-1][1:], data[i-1][1:])]
pprint(data)
Output (originally every sublist of data was just [0, 1, 2, 3]):
[[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 1, 2, 3],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 1, 2, 3]]
Hope this helps. Please let me know if there are any questions/concerns!

Pack consecutive duplicates of a particular item in a list into a list of lists

I want to read a list and then, select consecutive particular item from that list to store them in a New_list. Continue reading the list and again, select that particular item from that list and store them as another list in that New_list. Let's give an example:
nw_lst = []
lst = [1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1]
for i in range(0, len(lst), 1):
if lst[i] == 0:
nw_lst.append(lst[i])
print nw_lst
The output I am getting is:
[0, 0, 0, 0, 0, 0, 0]
I want to get:
[[0, 0, 0], [0, 0], [0, 0]]
You can use itertools.groupby:
import itertools as it
result = [list(g) for k, g in it.groupby(lst) if k == 0]
Here is a solution that works as long as you are only interested in consecutive zeros.
The idea is to make use of the split method of string. You just convert your list to string, split it on 1s, and then back to list.
lst = [1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1]
lst_str = "".join([str(x) for x in lst])
lst_str_zeros = lst_str.split("1")
new_lst = [[int(y) for y in x] for x in lst_zeros if x!=""]
print(new_lst)
[[0, 0, 0], [0, 0], [0, 0]]
Use a flag variable to check the status of the list in each iteration.
nw_lst = []
tmp = []
flag = 0
lst = [1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1]
for i in lst:
if i == 0:
if flag == 0:
tmp.append(i)
flag = 1
else:
tmp.append(i)
else :
flag = 0
if flag == 0 and len(tmp):
nw_lst.append(tmp)
tmp = []

Can someone help me simplify my Python function?

I'm working on my homework assignment in Python. I made a function that uses lists as input but I'm not very good at Python programming yet. The function works the way it's supose to but it's a mess. The only input that's really used is "values". This input is a list containing more lists. Inside the list there has to be atleast 2 lists. The max amount of lists allowed inside the input is 8. If the input only has 2 lists then the other 6 lists have to be [0]. An example for input: [[0, 1],[3, 8, 10]]. With the example input the output has to be:
[0, 3, 0, 0, 0, 0, 0, 0]
[0, 8, 0, 0, 0, 0, 0, 0]
[0, 10, 0, 0, 0, 0, 0, 0]
[1, 3, 0, 0, 0, 0, 0, 0]
[1, 8, 0, 0, 0, 0, 0, 0]
[1, 10, 0, 0, 0, 0, 0, 0]
Ofcourse the lists inside the input can be a lot bigger and there can be more. This is just a small example but I hope you get the idea. Have a look below for the code I made.
def mget(self, values):
val = [[0], [0], [0], [0], [0], [0], [0], [0]]
if self._steps[1] is 0:
print("Error: operation not possible on field \"" + self._name + "\"")
else:
for x in range(len(val)):
try:
if not values[x]:
val[x] = [0]
else:
val[x] = values[x]
except IndexError:
val[x] = [0]
for a in val[0]:
for b in val[1]:
for c in val[2]:
for d in val[3]:
for e in val[4]:
for f in val[5]:
for g in val[6]:
for h in val[7]:
Field.get(self, [a, b, c, d, e, f, g, h])
Thanks in advance!
Try this
from itertools import product
a = [[0, 1],[3, 8, 10]]
res = [list(lst) + [0] * (8 - len(lst)) for lst in product(*a)]
print(res)
Output:
[[0, 3, 0, 0, 0, 0, 0, 0], [0, 8, 0, 0, 0, 0, 0, 0], [0, 10, 0, 0, 0, 0, 0, 0], [1, 3, 0, 0, 0, 0, 0, 0], [1, 8, 0, 0, 0, 0, 0, 0], [1, 10, 0, 0, 0, 0, 0, 0]]

How to randomly pick an index of a given value in a list?

Assume I have the following 8x8 2D list:
[[0, 1, 0, 1, 0, 1, 0, 1],
[1, 0, 1, 0, 1, 0, 1, 0],
[0, 1, 0, 1, 0, 1, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[-1, 0, -1, 0, -1, 0, -1, 0],
[0, -1, 0, -1, 0, -1, 0, -1],
[-1, 0, -1, 0, -1, 0, -1, 0]]
How do I get a random index for the value "1" for example ?
Here's a nice one-liner with a nested list comprehension:
import random
random.choice([(i, j) for i, row in enumerate(x) for j, val in enumerate(row) if val == 1])
where x is your list. You just gather a list of indices (i, j) where val == 1, then randomly pick one.
If the list is rectangular (all elements are lists and these lists have the same length and the elements of these lists are numbers), we can boost the filtering process by using numpy instead:
from numpy import array, where
from random import choice
choice(array(where(a == 1)).T)
In case a is not an numpy array yet, we can convert it with:
choice(array(where(array(a) == 1)).T)
This then for instance returns:
>>> choice(array(where(a == 1)).T)
array([1, 2])
In case we want the result to be a list or tuple, we can call the constructor, like:
>>> tuple(choice(array(where(a == 1)).T))
(1, 6)
You could do something like:
indices = []
for row_idx in range(len(a)):
for col_idx in range(len(a[row_idx])):
num = a[row_idx][col_idx]
if num == 1:
indices.append((row_idx, col_idx))
import random
rand_idx = random.randrange(0, len(indices))
print indices[rand_idx]

Categories