Algorithm to create a binary-like pattern - python

I have two numbers: n and sp. I want to create a pattern of list elements with sp elements that rotate like binary digits up to n. To elaborate more on the second part, here is an example:
n = 2, sp = 3
[0, 0, 0]
[0, 0, 1]
[0, 1, 0]
[0, 1, 1]
[1, 0, 0]
[1, 0, 1]
[1, 1, 0]
[1, 1, 1]
Similarly:
n = 3, sp = 3
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 1, 0]
[0, 2, 0]
[0, 1, 1]
[0, 1, 2]
[0, 2, 1]
[0, 2, 2]
[1, 0, 0]
[1, 0, 1]
[1, 0, 2]
[1, 1, 0]
[1, 2, 0]
[1, 1, 1]
[1, 1, 2]
[1, 2, 1]
[1, 2, 2]
[2, 0, 0]
[2, 0, 1]
[2, 0, 2]
[2, 1, 0]
[2, 2, 0]
[2, 1, 1]
[2, 1, 2]
[2, 2, 1]
[2, 2, 2]
I wish to maintain the order that I have given in the examples, that is the LSB is assigned first, then the next bit, and so on...
I could not think of any tactic to solve such a problem. All I could figure out is to use sp to create a temporary list of size sp, for instance, if sp == 3, the temp_list can be [0 0 0]. Then we iterate in a manner so that we get the pattern.
There is no constraint on the complexity of the algorithm, although a shorter algorithm would be very great.

One simple way of doing it is:
def get_patterns(n, sp):
ans = []
def _get_patterns(so_far):
if len(so_far) == sp:
ans.append(so_far[:])
return
for i in range(n):
so_far.append(i)
_get_patterns(so_far)
so_far.pop()
_get_patterns([])
return ans
n = 3
sp = 3
assert get_patterns(n, sp) == sorted([
[0, 0, 0], [0, 0, 1], [0, 0, 2], [0, 1, 0],
[0, 2, 0], [0, 1, 1], [0, 1, 2], [0, 2, 1], [0, 2, 2],
[1, 0, 0], [1, 0, 1], [1, 0, 2], [1, 1, 0],
[1, 2, 0], [1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 2, 2],
[2, 0, 0], [2, 0, 1], [2, 0, 2], [2, 1, 0],
[2, 2, 0], [2, 1, 1], [2, 1, 2], [2, 2, 1], [2, 2, 2],
])

I wrote this
n = 4 # base
sp = 2 # length
def fix(num, base):
for j in range(len(num)):
if num[j] == base:
num[j] = 0
num[j+1] += 1
return num
num= [ 0 for _ in range(sp)]
print(num)
for i in range(n**sp -1):
num[0] += 1
num= fix(num, n)
print(num[::-1])

Related

assigning class name to list column in pandas

I have a column in dataframe of type list
categories
[0, 0, 2, 2, 2]
[0, 0, 2, 2]
[0, 0, 2, 2, 2]
[1, 1, 2, 2]
[2, 2, 0, 0]
[1, 0, 2, 3]
here is the sample list
li = [[0, 0, 2, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2, 2], [1, 1, 2, 2], [2, 2, 0, 0], [1, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2, 2], [0, 0, 2, 2], [2, 2, 0, 0], [2, 2, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [2, 2, 0, 0], [2, 2], [1, 1, 2], [0, 2, 2, 0], [0, 0, 2, 2], [0, 1], [0, 0], [0, 0, 2, 2], [0, 0], [0, 0, 2, 2], [0, 2, 2, 0], [2, 2, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [2, 2, 0, 0], [0, 0, 2, 2], [2, 2, 0, 1], [2, 2, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2, 2], [2, 1], [0, 0, 2, 2, 2], [2, 2, 0, 0], [2, 0], [2, 2, 0, 0], [0, 2], [0, 2, 2], [0, 0, 2, 2], [0, 2, 2, 0], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2, 2], [0, 0, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [3, 2, 0, 0], [0, 0], [0, 0, 2, 2], [0, 0, 2, 2, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [1, 3], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 2, 0, 2], [0, 0, 2, 2], [2, 2, 0, 0], [2, 2, 0, 0], [2, 2], [0, 0, 2, 2], [0, 2], [0, 0, 2, 2], [0, 0, 2, 2], [2, 2, 0], [2, 2, 0, 0], [0, 0, 2, 2], [0, 0, 2], [2], [0, 0, 2, 2], [2, 2, 2, 1, 1], [0, 0], [0, 3], [2, 2], [1, 2], [1,3]]
I want to create a new column (class_name) based on the following rule
The rules are based on priority and should be done one after other
if 1 and 3 are present, set class_name to class1
On the remaining rows, wherever 1 is present, set class_name to class2
On the remaining rows, wherever 3 is present, set class_name to class3
if 0 and 2 are present, set class_name to class4
On the remaining rows, wherever 0 is present, set class_name to class5
On the remaining rows, wherever 2 is present, set class_name to class6
What I have tried so far
df.loc[:, "class_name"] = None
for index, row in df.iterrows():
if row["class_name"] == None:
categories = list(row["categories"])
if 1 in categories and 3 in categories:
df.loc[index, "class_name"] = "class1"
Similarly, for each condition I have a separate loop.. but it's too slow.. is there a way to do it without looping ?
I think I understood the question correctly. And I tried something like this, it seems to work fine.
import pandas as pd
li = [[0, 0, 2, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2, 2], [1, 1, 2, 2], [2, 2, 0, 0], [1, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2, 2], [0, 0, 2, 2], [2, 2, 0, 0], [2, 2, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [2, 2, 0, 0], [2, 2], [1, 1, 2], [0, 2, 2, 0], [0, 0, 2, 2], [0, 1], [0, 0], [0, 0, 2, 2], [0, 0], [0, 0, 2, 2], [0, 2, 2, 0], [2, 2, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [2, 2, 0, 0], [0, 0, 2, 2], [2, 2, 0, 1], [2, 2, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2, 2], [2, 1], [0, 0, 2, 2, 2], [2, 2, 0, 0], [2, 0], [2, 2, 0, 0], [0, 2], [0, 2, 2], [0, 0, 2, 2], [0, 2, 2, 0], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2, 2], [0, 0, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [3, 2, 0, 0], [0, 0], [0, 0, 2, 2], [0, 0, 2, 2, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [1, 3], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 0, 2, 2], [0, 2, 0, 2], [0, 0, 2, 2], [2, 2, 0, 0], [2, 2, 0, 0], [2, 2], [0, 0, 2, 2], [0, 2], [0, 0, 2, 2], [0, 0, 2, 2], [2, 2, 0], [2, 2, 0, 0], [0, 0, 2, 2], [0, 0, 2], [2], [0, 0, 2, 2], [2, 2, 2, 1, 1], [0, 0], [0, 3], [2, 2], [1, 2], [1,3]]
df=pd.DataFrame(data={'category':li})
def check(x):
class_name=False
if all(item in x for item in [1,3]):
class_name='class1'
elif not all(item in x for item in [1,3]) and 1 in x:
class_name='class2'
elif not all(item in x for item in [1,3]) and 3 in x:
class_name='class3'
elif all(item in x for item in [0,2]):
class_name='class4'
elif 0 in x:
class_name='class5'
elif 2 in x:
class_name='class6'
else:
class_name='no_class'
return class_name
df['check']=df['category'].apply(lambda x: check(x))
print(df)
'''
category check
66 [1, 3] class1
92 [1, 3] class1
3 [1, 1, 2, 2] class2
5 [1, 0, 2, 2] class2
17 [1, 1, 2] class2
20 [0, 1] class2
32 [2, 2, 0, 1] class2
41 [2, 1] class2
87 [2, 2, 2, 1, 1] class2
91 [1, 2] class2
59 [3, 2, 0, 0] class3
89 [0, 3] class3
0 [0, 0, 2, 2, 2] class4
'''
Okay, so I ran your problem using a couple of different methods. The fastest of them all was using pandas.DataFrame.apply. Here's the code:
from __future__ import annotations
import pandas as pd
def class_name(row: list) -> str | None:
if 1 in row and 3 in row:
return "class1"
if 1 in row:
return "class2"
if 3 in row:
return "class3"
if 0 in row and 2 in row:
return "class4"
if 0 in row:
return "class5"
if 2 in row:
return "class6"
return None
# == How to use ============================
df["class_name"] = df["categories"].apply(class_name)
# Result using on a dataframe with 186000 rows:
"""
CPU times: user 80.9 ms, sys: 904 µs, total: 81.8 ms
Wall time: 82 ms
"""
Other Implementations I Tried
I've also tried some other implementations to compare. Here's them:
from __future__ import annotations
import pandas as pd
# == Code to Generate Sample DataFrame ==============
li = [
[0, 0, 2, 2, 2],
[0, 0, 2, 2],
[0, 0, 2, 2, 2],
[1, 1, 2, 2],
[2, 2, 0, 0],
[1, 0, 2, 2],
[0, 0, 2, 2],
[0, 0, 2, 2, 2],
[0, 0, 2, 2],
[2, 2, 0, 0],
[2, 2, 0, 0],
[0, 0, 2, 2],
[0, 0, 2, 2],
[0, 0, 2, 2],
[0, 0, 2, 2],
[2, 2, 0, 0],
[2, 2],
[1, 1, 2],
[0, 2, 2, 0],
[0, 0, 2, 2],
[0, 1],
[0, 0],
[0, 0, 2, 2],
[0, 0],
[0, 0, 2, 2],
[0, 2, 2, 0],
[2, 2, 2, 2],
[0, 0, 2, 2],
[0, 0, 2, 2],
[0, 0, 2, 2],
[2, 2, 0, 0],
[0, 0, 2, 2],
[2, 2, 0, 1],
[2, 2, 0, 0],
[0, 0, 2, 2],
[0, 0, 2, 2],
[0, 0, 2, 2],
[0, 0, 2, 2],
[0, 0, 2, 2],
[0, 0, 2, 2],
[0, 0, 2, 2, 2],
[2, 1],
[0, 0, 2, 2, 2],
[2, 2, 0, 0],
[2, 0],
[2, 2, 0, 0],
[0, 2],
[0, 2, 2],
[0, 0, 2, 2],
[0, 2, 2, 0],
[0, 0, 2, 2],
[0, 0, 2, 2],
[0, 0, 2, 2],
[0, 0, 2, 2, 2],
[0, 0, 2],
[0, 0, 2, 2],
[0, 0, 2, 2],
[0, 0, 2, 2],
[0, 0, 2, 2],
[3, 2, 0, 0],
[0, 0],
[0, 0, 2, 2],
[0, 0, 2, 2, 2, 2],
[0, 0, 2, 2],
[0, 0, 2, 2],
[0, 0, 2, 2],
[1, 3],
[0, 0, 2, 2],
[0, 0, 2, 2],
[0, 0, 2, 2],
[0, 0, 2, 2],
[0, 0, 2, 2],
[0, 2, 0, 2],
[0, 0, 2, 2],
[2, 2, 0, 0],
[2, 2, 0, 0],
[2, 2],
[0, 0, 2, 2],
[0, 2],
[0, 0, 2, 2],
[0, 0, 2, 2],
[2, 2, 0],
[2, 2, 0, 0],
[0, 0, 2, 2],
[0, 0, 2],
[2],
[0, 0, 2, 2],
[2, 2, 2, 1, 1],
[0, 0],
[0, 3],
[2, 2],
[1, 2],
[1, 3],
]
def make_df(size=1):
return pd.DataFrame({'categories': [v for i in range(size) for v in li]})
# == Implementation 1 ============================
def class_name2(row: list) -> str | None:
categories = row["categories"]
if 1 in categories and 3 in categories:
return "class1"
if 1 in categories:
return "class2"
if 3 in categories:
return "class3"
if 0 in categories and 2 in categories:
return "class4"
if 0 in categories:
return "class5"
if 2 in categories:
return "class6"
return None
df = make_df(2000)
df["class_name"] = df.apply(class_name2, axis=1)
# Result:
"""
CPU times: user 1.69 s, sys: 17 ms, total: 1.71 s
Wall time: 1.71 s
"""
# == Implementation 2 ============================
# This is your original implementation
df = make_df(2000)
df.loc[:, "class_name"] = None
for index, row in df.iterrows():
if row["class_name"] == None:
categories = list(row["categories"])
if 1 in categories and 3 in categories:
df.loc[index, "class_name"] = "class1"
elif 1 in categories:
df.loc[index, "class_name"] = "class2"
elif 3 in categories:
df.loc[index, "class_name"] = "class3"
elif 0 in categories and 2 in categories:
df.loc[index, "class_name"] = "class4"
elif 0 in categories:
df.loc[index, "class_name"] = "class5"
elif 2 in categories:
df.loc[index, "class_name"] = "class6"
# Result:
"""
CPU times: user 24.2 s, sys: 65.6 ms, total: 24.3 s
Wall time: 24.5 s
"""
# == Implementation 3 ============================
# This is your original implementation without the if statement
df = make_df(2000)
df.loc[:, "class_name"] = None
for index, row in df.iterrows():
categories = list(row["categories"])
if 1 in categories and 3 in categories:
df.loc[index, "class_name"] = "class1"
elif 1 in categories:
df.loc[index, "class_name"] = "class2"
elif 3 in categories:
df.loc[index, "class_name"] = "class3"
elif 0 in categories and 2 in categories:
df.loc[index, "class_name"] = "class4"
elif 0 in categories:
df.loc[index, "class_name"] = "class5"
elif 2 in categories:
df.loc[index, "class_name"] = "class6"
# Result:
"""
CPU times: user 24 s, sys: 91.2 ms, total: 24.1 s
Wall time: 24.3 s
"""
# == Implementation 4 ============================
# This is your original implementation without the if statement
# and the list conversion
df = make_df(2000)
df.loc[:, "class_name"] = None
for index, row in df.iterrows():
categories = row["categories"]
if 1 in categories and 3 in categories:
df.loc[index, "class_name"] = "class1"
elif 1 in categories:
df.loc[index, "class_name"] = "class2"
elif 3 in categories:
df.loc[index, "class_name"] = "class3"
elif 0 in categories and 2 in categories:
df.loc[index, "class_name"] = "class4"
elif 0 in categories:
df.loc[index, "class_name"] = "class5"
elif 2 in categories:
df.loc[index, "class_name"] = "class6"
# Result:
"""
CPU times: user 23.4 s, sys: 80 ms, total: 23.5 s
Wall time: 24.2 s
"""
# == Implementation 5 ============================
# Using `swifter`. Install swifter before trying this one:
# pip install swifter
import swifter
def class_name(row: list) -> str | None:
if 1 in row and 3 in row:
return "class1"
if 1 in row:
return "class2"
if 3 in row:
return "class3"
if 0 in row and 2 in row:
return "class4"
if 0 in row:
return "class5"
if 2 in row:
return "class6"
return None
df = make_df(2000)
df["class_name"] = df["categories"].swifter.apply(class_name)
# Result:
"""
CPU times: user 572 ms, sys: 11 ms, total: 582 ms
Wall time: 930 ms
"""
Summary
Here's a summary of all the results:
Implementation
Total Time
Times Faster
Best
82 ms
300x
Implementation 1
1.71 s
14.3x
Implementation 2
24.5 s
1x
Implementation 3
24.3 s
1.008x
Implementation 4
24.2 s
1.012x
Implementation 5
930 ms
26x

get lines where value does not exist

I'm trying to get from 2D list the lines where value = 2 does not exists:
[[0, 0, 1, 1],
[2, 1, 0, 2],
[2, 2, 2, 2],
[0, 0, 1, 0]]
I've been using:
for i in range(len(list)):
if list[i] in [list]:
# dot stuff
the problem here is that evrytime the code is using the actual line which is list[i] and ignore the the rest even if 2 does not exists on it
hope Iwas clear
Thank you
something like the below
lst = [[0, 0, 1, 1],
[2, 1, 0, 2],
[2, 2, 2, 2],
[0, 0, 1, 0]]
lst = [x for x in lst if 2 not in x]
print(lst)
output
[[0, 0, 1, 1], [0, 0, 1, 0]]
Is this your expected output?
[0, 0, 1, 1]
[0, 0, 1, 0]
This is the working code:
a = [[0, 0, 1, 1],
[2, 1, 0, 2],
[2, 2, 2, 2],
[0, 0, 1, 0]]
for i in range(len(a)):
if 2 not in a[i]:
print(a[i])

Transpose of a 3d list

I have tried this the below mentioned code:
counts=[[[(col.count(i)) for i in range(1,n)] for col in matrix] for matrix in lists]
print(counts)
and the code gives me
[[[1, 1, 1, 1, 0], [1, 1, 1, 0, 1], [1, 1, 0, 1, 1]], [[4, 0, 0, 0, 0], [1, 2, 1, 0, 0], [0, 0, 1, 3, 0]]]
this output
here 3, 5 element list created. I want 5, 3 element list. The output should look like:
[[[1, 1, 1], [1, 0, 1], [1, 1, 0], [1, 1, 1], [0, 1, 1]], [[4, 0, 0], [0, 0, 1], [2, 1, 0], [0, 0, 0], [1, 3, 0]]]
what kind of work should be performed on 'counts' list so that I get this desired output.
you don't really transpose anything as far as i can tell; this is just a reshaping. numpy lets you do that this way:
import numpy as np
lst = [[[1, 1, 1, 1, 0], [1, 1, 1, 0, 1], [1, 1, 0, 1, 1]],
[[4, 0, 0, 0, 0], [1, 2, 1, 0, 0], [0, 0, 1, 3, 0]]]
arr = np.array(lst)
res = arr.reshape((2, 5, 3))
which gives:
[[[1 1 1]
[1 0 1]
[1 1 0]
[1 1 1]
[0 1 1]]
[[4 0 0]
[0 0 1]
[2 1 0]
[0 0 0]
[1 3 0]]]

Weird appearance when append item in generator to list in Python

I was trying to generate a p-level pascal triangle using the code below:
def triangles(p):
L = [1]
count = 0
while count < p:
yield L
L.append(0)
L = [L[i - 1] + L[i] for i in range(len(L))]
count = count + 1
def pascal(p):
result = []
t = triangles(p)
for i in range(p):
result.append(next(t))
return result
The expected result of pascal(5) should be [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]], but I got [[1, 0], [1, 1, 0], [1, 2, 1, 0], [1, 3, 3, 1, 0], [1, 4, 6, 4, 1, 0]] instead.
I tried to print each i in triangles(5),
for i in triangles(5):
print i
and the result is:
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
Then I tried:
result = []
for i in triangles(5):
print result
print i
result.append(i)
print result
And the output looks like:
[] # result in step 1, before append
[1] # 1st item in triangles(5)
[[1]] # result in step 1, after append
[[1, 0]] # result in step 2, before append, here's where it changes
[1, 1]
[[1, 0], [1, 1]]
[[1, 0], [1, 1, 0]]
[1, 2, 1]
[[1, 0], [1, 1, 0], [1, 2, 1]]
[[1, 0], [1, 1, 0], [1, 2, 1, 0]]
[1, 3, 3, 1]
[[1, 0], [1, 1, 0], [1, 2, 1, 0], [1, 3, 3, 1]]
[[1, 0], [1, 1, 0], [1, 2, 1, 0], [1, 3, 3, 1, 0]]
[1, 4, 6, 4, 1]
[[1, 0], [1, 1, 0], [1, 2, 1, 0], [1, 3, 3, 1, 0], [1, 4, 6, 4, 1]]
Why append will change the previous value in list?
L.append(0) changes the list after you've yielded it, because objects in python are shared.
Try
L = L + [0]
instead, to create a new list instead of changing it in-place.

Permutations in python without libraries

I am trying to produce a function that should takes as input a range, and for that range should be return all the possible permutation of that range without use any library.
for example:
per(range(3))
should return:
[[0, 1, 2], [1, 0, 2], [1, 2, 0], [0, 2, 1], [2, 0, 1], [2, 1, 0]]
I have done the following but i get an empty list.
def per(l):
return [l[i]+p for i in range(len(l))for p in per(l[:i] + l [i+1:])]
Does anyone know why i get the empty list and how to solve it?
The issue is that the end condition for you would be when the length of list l is 0 and that returns an empty list back. Hence when length of list is 1, the inner loop never actually runs and hence this also returns an empty list back , and this keeps on happenning and you always get empty lists.
An fix would be to make the end condition when the length of list is 1, and you should return lists of lists, not simple lists. Example -
def per(l):
if len(l) == 1:
return [l]
return [[l[i]] + p for i in range(len(l))for p in per(l[:i] + l [i+1:])]
Demo -
>>> def per(l):
... if len(l) == 1:
... return [l]
... return [[l[i]] + p for i in range(len(l))for p in per(l[:i] + l [i+1:])]
...
>>>
>>> per([2])
[[2]]
>>> per([0,1,2])
[[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]]
>>> per([0,1,2, 3])
[[0, 1, 2, 3], [0, 1, 3, 2], [0, 2, 1, 3], [0, 2, 3, 1], [0, 3, 1, 2], [0, 3, 2, 1], [1, 0, 2, 3], [1, 0, 3, 2], [1, 2, 0, 3], [1, 2, 3, 0], [1, 3, 0, 2], [1, 3, 2, 0], [2, 0, 1, 3], [2, 0, 3, 1], [2, 1, 0, 3], [2, 1, 3, 0], [2, 3, 0, 1], [2, 3, 1, 0], [3, 0, 1, 2], [3, 0, 2, 1], [3, 1, 0, 2], [3, 1, 2, 0], [3, 2, 0, 1], [3, 2, 1, 0]]
>>> len(per([0,1,2, 3]))
24

Categories

Resources