Let's say I have a list of pattern [2, 1] and given a length = 5.
The pattern means that there are sets of 2 and 1 'ones' in the list in that order in a list of length = 5.
Also the space or 0 between successive groups has to be at least one.
What I've tried is:
for curr_col in pattern_list:
curr_pattern = curr_col
example_combo = [0] * dim0
idx, group_strt_idxs = 0, []
for num in curr_pattern :
group_strt_idxs.append(idx)
for i in range(num ):
example_combo[idx] = 1
idx += 1
if idx < dim0 and dim0 > 1:
example_combo[idx] = 0
idx += 1
print('ex', example_combo)
Please help!
The problem is to put the zeros into len(constraints_list) + 1 buckets. The first and last one can contain 0 or more zeros, the intermediate ones must contain at least one.
We generate the possible repartitions in the repartitions function. It is then easy to build the corresponding list:
from itertools import zip_longest
def repartitions(number, buckets, start=None):
if start is None:
start = []
mini = 0 # first sequence of zeros can be empty
else:
mini = 1 # others contain at least one zero
if buckets == 1:
# last bucket, we put all remaining zeros here
start = start + [number]
yield start
else:
for i in range(mini, number-buckets+3):
# we have to keep at least 1 zero for each other bucket
# except the last one.
current = start + [i]
yield from repartitions(number-i, buckets-1, current)
def permutations_with_constraints(constraints_list, length):
number_of_zeros = length - sum(constraints_list)
buckets = len(constraints_list) + 1
for rep in repartitions(number_of_zeros, buckets):
out = sum(([0]*zeros + [1]*ones
for zeros, ones in zip_longest(rep, constraints_list, fillvalue=0)), [])
yield out
Some examples:
print(list(permutations_with_constraints([1, 2], 5)))
# [[1, 0, 1, 1, 0], [1, 0, 0, 1, 1], [0, 1, 0, 1, 1]]
print(list(permutations_with_constraints([2, 3, 2], 11)))
# [[1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0],
# [1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0],
# [1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1],
# [1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0],
# [1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1],
# [1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1],
# [0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0],
# [0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1],
# [0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1],
# [0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1]]
Some explanations about the sum, as you asked in comments:
We have a rep list, and a one item shorter constraints list. We zip them with zip_longest and a fillvalue=0, which gives us [(rep[0], constraints[0]), (rep[1], constraints[1]), ... (rep[-1], 0)]. (It's really a generator, not a list, but this doesn't change anything to the explanation). The last 0 fills the missing value in constraints.
We then build a list from each tuple. For example, (2, 3) will give us [0, 0, 1, 1, 1]. sum then adds these lists, using [] as a start value.
Since the length of the groups of 1's are already given, the recursion can determine the placing for each:
def generate_groups(d, fill=1):
return [[fill]*i for i in d]
def all_groups(_d, _len):
def groupings(d, current = []):
if sum(not i for i in current) == d and sum(i == '*' for i in current) == len(_d):
yield current
else:
if sum(not i for i in current) < d:
yield from groupings(d, current+[0])
if not current or not current[-1]:
yield from groupings(d, current+['*'])
return [(lambda x, y:[c for h in y for c in ([h] if not h else next(x))])(iter(generate_groups(_d)), i)
for i in groupings(_len-sum(_d))]
print(all_groups([2, 1], 5))
print(all_groups([2, 3, 2], 11))
Output:
[[0, 1, 1, 0, 1], [1, 1, 0, 0, 1], [1, 1, 0, 1, 0]]
[[0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1], [0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1], [0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1], [0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0], [1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1], [1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1], [1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0], [1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1], [1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0], [1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0]]
Related
I have a collection of lists of integer values in python like the following:
[0, 0, 1, 0, 1, 0, 0, 2, 1, 1, 1, 2, 1]
Now I would like to have a somewhat "smoothed" sequence where each value with the same preceding and following value (which both differ from the central value in question) is replaced with this preceeding-following value. So my list above becomes:
[0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 1, 1]
(The order or procession is from left to right, just to reconcile possible conflicting groupings.)
How could I achieve list?
Bonus: same as above with possible parametrization how many preceeding-following values must occur to change the central value (2-2 or 3-3 instead of just 1-1).
A straightforward loop should do the trick:
_list = [0, 0, 1, 0, 1, 0, 0, 2, 1, 1, 1, 2, 1]
for i in range(1, len(_list)-1):
if _list[i-1] == _list[i+1]:
_list[i] = _list[i-1]
print(_list)
Output:
[0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 1, 1]
arr = [0, 0, 1, 0, 1, 0, 0, 2, 1, 1, 1, 2, 1]
res = [arr[0]]
i = 0
for i in range(1,len(arr)):
if res[i-1] not in arr[i:i+2]:
res.append(arr[i])
else:
res.append(res[i-1] )
print(res)
To allow the number of preceding / following values to be changed, you can create a 'pad' the list and iterate through a moving window on the padded list to check if all surrounding values are the same.
def smooth(lst, values=1, padding=None):
padded = [padding] * values + lst + [padding] * values
for i, n in enumerate(lst):
surrounding = set(padded[i:i+values] + padded[i+values+1:i+values*2+1])
if len(surrounding) == 1:
yield surrounding.pop()
else:
yield n
print(list(smooth([0, 0, 1, 0, 1, 0, 0, 2, 1, 1, 1, 2, 1]))) # [0, 0, 0, 1, 0, 0, 0, 2, 1, 1, 1, 1, 1]
If your input list may contain None, choose a different padding parameter when calling the generator.
This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 1 year ago.
I am trying to do a simple task in python and I cannot figure out why it is failing at the append() function.
d = pd.DataFrame([1,2,3,4,5,6,1,2,3,])
d.columns = ['prediction_num']
def cumulative_vector(df):
vector = [0,0,0,0,0,0,0,0,0]
vectorL = []
for i in df.prediction_num.values:
vector[i] += 1
print(vector)
vectorL.append(vector)
df['cumulative_histogram'] = vectorL
print(df.cumulative_histogram)
return df
cumulative_vector(d)
When I print out the vector variable in the loop, I get the right output, which is:
[0, 1, 0, 0, 0, 0, 0, 0, 0]
[0, 1, 1, 0, 0, 0, 0, 0, 0]
[0, 1, 1, 1, 0, 0, 0, 0, 0]
[0, 1, 1, 1, 1, 0, 0, 0, 0]
[0, 1, 1, 1, 1, 1, 0, 0, 0]
[0, 1, 1, 1, 1, 1, 1, 0, 0]
[0, 2, 1, 1, 1, 1, 1, 0, 0]
[0, 2, 2, 1, 1, 1, 1, 0, 0]
[0, 2, 2, 2, 1, 1, 1, 0, 0]
However, when I print the newly created df.cumulative_histogram column, I get this:
0 [0, 2, 2, 2, 1, 1, 1, 0, 0]
1 [0, 2, 2, 2, 1, 1, 1, 0, 0]
2 [0, 2, 2, 2, 1, 1, 1, 0, 0]
3 [0, 2, 2, 2, 1, 1, 1, 0, 0]
4 [0, 2, 2, 2, 1, 1, 1, 0, 0]
5 [0, 2, 2, 2, 1, 1, 1, 0, 0]
6 [0, 2, 2, 2, 1, 1, 1, 0, 0]
7 [0, 2, 2, 2, 1, 1, 1, 0, 0]
8 [0, 2, 2, 2, 1, 1, 1, 0, 0]
Why does the column only contain the last value of vector in the loop and not each iterative value? It is appended during each loop, so I am unsure what I am missing.
For loop is reusing your old vector object. This means that at each iteration you only have one list that you are modifying. Printing is working fine because you are printing the state of the list at a specific point in time.
r = []
for idx in range(0,10):
r.append(idx)
print(r)
---
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
for idx in range(0,10):
r = []
r.append(idx)
print(r)
---
[9]
To fix your specific case, add [:] to append a copy of the list instead.
# ...
for i in df.prediction_num.values:
vector[i] += 1
print(vector)
vectorL.append(vector[:]) # vector -> vector[:] here
I have a (long) list in which zeros and ones appear at random:
list1 = [1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1]
1.I want to get another list
the sum of the list up to where 0 appears
where 0 appears, retain 0 in the list
list2 = [3, 0, 2, 0, 1, 0, 3]
It should work for corner cases as well like zeroes at start or end
list1 = [0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0]
list2 = [0, 3, 0, 2, 0, 1, 0, 3, 0]
You can use itertools.groupby:
from itertools import groupby
list1 = [1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1]
out = []
for v, g in groupby(list1):
if v:
out.append(sum(g))
else:
out.extend(g) # or out.append(0) if you want to keep only single zero
print(out)
Prints:
[3, 0, 2, 0, 1, 0, 3]
For list1 = [0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0] it prints:
[0, 3, 0, 2, 0, 1, 0, 3, 0]
If you want to do it the plain-vanilla way without importing anything, you could do:
list2 = [1] if list1[0] else [0] # Initialise
for i in range(1, len(list1)):
if list1[i] and list1[i-1]:
list2[-1] += 1
elif list1[i]:
list2.append(1)
elif list1[i-1]:
list2.append(0)
For
[1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1]
[0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1]
[1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0]
this gives:
[3, 0, 2, 0, 1, 0, 3]
[0, 3, 0, 2, 0, 1, 0, 3]
[3, 0, 2, 0, 1, 0, 3, 0]
respectively.
Currently, I have two functions: char2bin and segmentString.
segmentString takes a string and a fill character and returns lists of 8 character strings. For example, if there is a 13 character string, it splits it into a list of two strings where the second string has 3 fill characters to make it a complete 8.
>>>segmentString("Hello, World!", "-")
['Hello, W', 'orld!---']
char2bin takes individual string characters (single character) and turns them into a list of 8 bits. It does not work for multiple character strings. For example,
>>>char2bin('a')
[0,1,1,0,0,0,0,1]
>>>char2bin('abc')
(ERROR)
I need to create a function (in this example, let's call it framer) that takes the result from segmentString and convert it into a list of bits, where each list of bits are contained in a separate list within a list.
For example, from the segmentString function, this would create a list of two strings. Each letter of each separate string is converted into a list of bits, and each list of bits is contained as a list for each string.
>>>F=framer("Hello, World!", "-")
>>>F
[[[0, 1, 0, 0, 1, 0, 0, 0], [0, 1, 1, 0, 0, 1, 0, 1], [0,1, 1, 0, 1, 1, 0, 0], [0, 1, 1, 0, 1, 1, 0, 0], [0, 1, 1, 0, 1, 1,1,1], [0, 0, 1, 0, 1, 1, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], [0, 1,1, 1,0, 1, 1, 1]], [[0, 1, 1, 0, 1, 1, 1, 1], [0, 1, 1, 1, 0, 0,1, 0], [0,1, 1, 0, 1, 1, 0, 0], [0, 1, 1, 0, 0, 1, 0, 0], [0, 0,1, 0, 0, 0, 0,1], [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1,1, 0], [0, 1, 1, 1,1, 1, 1, 0]]]
As you can see, there is one general list that contains two lists that contain 8 lists of bits, which were converted from a string character by char2bin.
How would I do this?
You can use a list comprehension for this:
def char2bin(byte):
return list(map(int, format(byte, '08b')))
def segmentString(text, padding, chunksize):
for index in range(0, len(text), chunksize):
yield text[index:index + chunksize].ljust(chunksize, padding)
def framer(text, padding='-', chunksize=8, encoding='utf8'):
return [[char2bin(byte) for byte in segment] for segment in
segmentString(text.encode(encoding), padding.encode(encoding), chunksize)]
This uses utf8 encoding, but since your input text is all ascii characters, there's one byte per character.
>>> framer('Hello, World!')
[[[0, 1, 0, 0, 1, 0, 0, 0],
[0, 1, 1, 0, 0, 1, 0, 1],
[0, 1, 1, 0, 1, 1, 0, 0],
[0, 1, 1, 0, 1, 1, 0, 0],
[0, 1, 1, 0, 1, 1, 1, 1],
[0, 0, 1, 0, 1, 1, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 0, 1, 1, 1]],
[[0, 1, 1, 0, 1, 1, 1, 1],
[0, 1, 1, 1, 0, 0, 1, 0],
[0, 1, 1, 0, 1, 1, 0, 0],
[0, 1, 1, 0, 0, 1, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 1],
[0, 0, 1, 0, 1, 1, 0, 1],
[0, 0, 1, 0, 1, 1, 0, 1],
[0, 0, 1, 0, 1, 1, 0, 1]]]
Non-ascii characters require multiple bits to encode.
>>> framer('💩', padding='\x00')
[[[1, 1, 1, 1, 0, 0, 0, 0],
[1, 0, 0, 1, 1, 1, 1, 1],
[1, 0, 0, 1, 0, 0, 1, 0],
[1, 0, 1, 0, 1, 0, 0, 1],
[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]]]
You could either use list comprehensions or make use of the itertools module.
You can learn more about list comprehensions here, and more about itertootls here.
You can use below code to achieve your goal.
def segment_string(s, fill_by):
l = []
while s:
if len(s) < 8:
s = s + (fill_by) * (8 - len(s))
l.append(s[0:8])
s = s[8:]
return l # ['Hello, W', 'orld!---']
def char2bin(ch):
a = bin(ord(ch))[2:]
l = [int(c) for c in a]
if len(l) < 8:
l = ([0] * (8 - len(l))) + l # Adding extra 0s to front (if len(l) < 8)
return l # [0, 1, 0, 0, 1, 0, 0, 0]
def framer(s, fill_by='-'):
segments = segment_string(s, fill_by) # Calling segment_string()
print(segments)
arr = []
for segment in segments:
arr2 = []
for ch in segment:
arr3 = char2bin(ch); # Calling char2bin()
arr2.append(arr3)
arr.append(arr2)
return arr # final list to be returned
if __name__ == "__main__":
f = framer('Hello, World!', '~')
print(f)
Output »
[[[0, 1, 0, 0, 1, 0, 0, 0], [0, 1, 1, 0, 0, 1, 0, 1], [0, 1, 1, 0, 1, 1, 0, 0], [0, 1, 1, 0, 1, 1, 0, 0], [0, 1, 1, 0, 1, 1, 1, 1], [0, 0, 1, 0, 1, 1, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], [0, 1, 0, 1, 0, 1, 1, 1]], [[0, 1, 1, 0, 1, 1, 1, 1], [0, 1, 1, 1, 0, 0, 1, 0], [0, 1, 1, 0, 1, 1, 0, 0], [0, 1, 1, 0, 0, 1, 0, 0], [0, 0, 1, 0, 0, 0, 0, 1], [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0]]]
# >>> bin(126)
# '0b1111110'
# >>>
# >>> chr(126)
# '~'
# >>>
I am trying to count the number of occurrences a 0 occurs in two lists together and save that number using python. I am trying to put it into a third list using 'list comprehension' commands but I am not getting the output I want.
My two lists are:
list1 = [0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1]
list2 = [0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0]
So, anytime there is a 0 occuring in the same place in each list I would like to append '0' into a new list. I would like to do the same thing with the ones.
the new list should look like:
newlist = [0,1,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1]
Thanks for the help in advance, I've been trying to figure out how to do this for several hours now to no avail!
You can use a list comprehension, like this:
answer = [x for x, y in zip(list1, list2) if x == y]
Alternatively, you can solve it without list comprehensions by using simple list operations:
answer = []
for x, y in zip(list1, list2):
if x == y:
answer.append(x)
In both cases, answerwill be:
[0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
[x or y for x,y zip(list1, list2)]
[0 if x == (0,0) else 1 for x in zip(list1,list2)]
list1 = [0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1]
list2 = [0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0]
temp = [ list1[i] if list1[i] == list2[i] else 2 for i in range( 0, len(list1) )]
answer = [value for value in temp if value != 2]
print( answer )
Solution
If you want list consisting of 0 and 1 in order of 0 or 1 appearing at the same position in both lists, then you can use the following list comprehension:
result = [a for a, b in zip(list1, list2) if a==b]
Test
Testing your values however:
>>> newlist = [a for a, b in zip(list1, list2) if a==b]
>>> newlist
[0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
you see that the result is not equal to what you have been expecting:
>>> newlist == [0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
False
So the question for you is: is the expected result you have provided a correct one?