将二进制列表中的 0 更改为 1,这样就不会有超过 N 个连续的零
Change 0's to 1's in a binary list so that there wouldn't be more than N consecutive zeros
考虑以下列表:
l = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0]
1
将列表细分为 5 个部分:
l = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0]
我希望每个部分在 1
之前的连续零(如果可能)不超过 n
个,但您不能删除当前的 1
。也不能有 1 相互跟随。
简单示例:假设 n = 3,l
应该是:
l = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0]
对于 n = 2 它将是:
l = [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1]
对于第一部分,我没有在两个零之后包含一个 1
,因为这样你就会有两个 1
彼此跟随。
知道我该怎么做吗?
这是我尝试过的:
import numpy as np
max_number_of_cells_per_list = 3
l = [0, 0, 0, 1, 0, 0, 0,0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0]
print(l)
# Find position of 1
pos_1 =[i for i,x in enumerate(l) if x == 1]
# Get number of cells
pos_1.insert(0,0)
numb_cells = np.diff(pos_1)
n = np.round(np.divide(numb_cells,max_number_of_cells_per_list))
k = 0
j = 0
for i,li in enumerate(l):
if l[i] == 1:
if n[k] > 1:
add = int((i-j)/n[k])
for jj in range(int(n[k])):
if jj == n[k]-1:
jj = i
else:
jj += add
l[jj] = 1
k += 1
j = i
print(l)
如果您尝试 运行 代码,您会发现它与 l
没有区别。我不明白为什么...但如果您有 better/different 个想法,我不太愿意找出我的错误。 :)
由于您使用的是 NumPy,这里有一个使用它的解决方案。请注意,它没有矢量化,我不确定你是否可以对其进行矢量化,因为我们必须对数组执行分组操作,而 NumPy 没有太多的功能(尽管我可能只是不这样做)看到它了)。
我将使用 np.split
获取 [0, ..., 1]
组,然后检查两种情况:首先,对于实际上不以 1
结尾的数组(一个可能的组在数组的末尾),以及具有超过 n + 2
个零的数组。然后我在每个 n + 1
位置插入 1
以确保不会有两个 1 在一起。
import numpy as np
a = np.array([0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0])
n = 3 # or n = 2, or any other n >= 0 value
result = []
for array in np.split(a.copy(), np.where(a == 1)[0] + 1):
last_index = -2 if array[-1] == 1 else None
array[n:last_index:n + 1] = 1
result.append(array)
np.concatenate(result)
# for n = 3: array([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0])
# for n = 2: array([0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1])
或者,我们可以只对 1
的索引进行操作,而不是将数组分成多个部分并对它们进行操作。例如,这里我得到 1
的初始索引,并在使用 range
:
之间添加更多索引
from itertools import tee
l = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0]
n = 3
def pairwise(iterable):
"""s -> (s0, s1), (s1, s2), (s2, s3), ..."""
a, b = tee(iterable)
next(b, None)
return zip(a, b)
def one_indices(seq, n):
"""Returns new indices where we will put 1s"""
indices = [index + 1 for index, value in enumerate(seq) if value == 1]
complete_groups_count = len(indices) # those that end with 1
indices = [0, *indices, len(seq)]
for group_index, (start, end) in enumerate(pairwise(indices), start=1):
if group_index <= complete_groups_count:
yield from range(start + n, end - 2, n + 1)
yield end - 1
else: # last group that doesn't end with 1
yield from range(start + n, end, n + 1)
result = [0] * len(l)
for index in one_indices(l, 3):
result[index] = 1
result
# for n = 3: [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0]
# for n = 2: [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1]
这可能比第一个示例中的拆分和连接数组更有效,但也更难阅读。
最后,作为奖励,这里有一个使用 pandas 的解决方案。我在你之前的相关问题中看到你正在使用它,所以你可能会觉得它有用:
from functools import partial
import pandas as pd
def fill_ones(series, n):
last_index = -2 if series.iloc[-1] == 1 else None
series.iloc[n:last_index:n + 1] = 1
return series
l = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0]
s = pd.Series(l)
groups = s.shift().eq(1).cumsum()
fill_w_distance_3 = partial(fill_ones, n=3)
s.groupby(groups).transform(fill_w_distance_3).tolist()
# [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0]
fill_w_distance_2 = partial(fill_ones, n=2)
s.groupby(groups).transform(fill_w_distance_2).tolist()
# [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1]
考虑以下列表:
l = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0]
1
将列表细分为 5 个部分:
l = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0]
我希望每个部分在 1
之前的连续零(如果可能)不超过 n
个,但您不能删除当前的 1
。也不能有 1 相互跟随。
简单示例:假设 n = 3,l
应该是:
l = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0]
对于 n = 2 它将是:
l = [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1]
对于第一部分,我没有在两个零之后包含一个 1
,因为这样你就会有两个 1
彼此跟随。
知道我该怎么做吗?
这是我尝试过的:
import numpy as np
max_number_of_cells_per_list = 3
l = [0, 0, 0, 1, 0, 0, 0,0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0]
print(l)
# Find position of 1
pos_1 =[i for i,x in enumerate(l) if x == 1]
# Get number of cells
pos_1.insert(0,0)
numb_cells = np.diff(pos_1)
n = np.round(np.divide(numb_cells,max_number_of_cells_per_list))
k = 0
j = 0
for i,li in enumerate(l):
if l[i] == 1:
if n[k] > 1:
add = int((i-j)/n[k])
for jj in range(int(n[k])):
if jj == n[k]-1:
jj = i
else:
jj += add
l[jj] = 1
k += 1
j = i
print(l)
如果您尝试 运行 代码,您会发现它与 l
没有区别。我不明白为什么...但如果您有 better/different 个想法,我不太愿意找出我的错误。 :)
由于您使用的是 NumPy,这里有一个使用它的解决方案。请注意,它没有矢量化,我不确定你是否可以对其进行矢量化,因为我们必须对数组执行分组操作,而 NumPy 没有太多的功能(尽管我可能只是不这样做)看到它了)。
我将使用 np.split
获取 [0, ..., 1]
组,然后检查两种情况:首先,对于实际上不以 1
结尾的数组(一个可能的组在数组的末尾),以及具有超过 n + 2
个零的数组。然后我在每个 n + 1
位置插入 1
以确保不会有两个 1 在一起。
import numpy as np
a = np.array([0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0])
n = 3 # or n = 2, or any other n >= 0 value
result = []
for array in np.split(a.copy(), np.where(a == 1)[0] + 1):
last_index = -2 if array[-1] == 1 else None
array[n:last_index:n + 1] = 1
result.append(array)
np.concatenate(result)
# for n = 3: array([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0])
# for n = 2: array([0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1])
或者,我们可以只对 1
的索引进行操作,而不是将数组分成多个部分并对它们进行操作。例如,这里我得到 1
的初始索引,并在使用 range
:
from itertools import tee
l = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0]
n = 3
def pairwise(iterable):
"""s -> (s0, s1), (s1, s2), (s2, s3), ..."""
a, b = tee(iterable)
next(b, None)
return zip(a, b)
def one_indices(seq, n):
"""Returns new indices where we will put 1s"""
indices = [index + 1 for index, value in enumerate(seq) if value == 1]
complete_groups_count = len(indices) # those that end with 1
indices = [0, *indices, len(seq)]
for group_index, (start, end) in enumerate(pairwise(indices), start=1):
if group_index <= complete_groups_count:
yield from range(start + n, end - 2, n + 1)
yield end - 1
else: # last group that doesn't end with 1
yield from range(start + n, end, n + 1)
result = [0] * len(l)
for index in one_indices(l, 3):
result[index] = 1
result
# for n = 3: [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0]
# for n = 2: [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1]
这可能比第一个示例中的拆分和连接数组更有效,但也更难阅读。
最后,作为奖励,这里有一个使用 pandas 的解决方案。我在你之前的相关问题中看到你正在使用它,所以你可能会觉得它有用:
from functools import partial
import pandas as pd
def fill_ones(series, n):
last_index = -2 if series.iloc[-1] == 1 else None
series.iloc[n:last_index:n + 1] = 1
return series
l = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0]
s = pd.Series(l)
groups = s.shift().eq(1).cumsum()
fill_w_distance_3 = partial(fill_ones, n=3)
s.groupby(groups).transform(fill_w_distance_3).tolist()
# [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0]
fill_w_distance_2 = partial(fill_ones, n=2)
s.groupby(groups).transform(fill_w_distance_2).tolist()
# [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1]