前向填充位数组的最有效方法

Posted

技术标签:

【中文标题】前向填充位数组的最有效方法【英文标题】:Most efficient way to forward fill a bit array 【发布时间】:2022-01-20 14:50:30 【问题描述】:

假设您有一个随机填充的位数组(任何数据类型都可以。例如列表、np.array、位数组、位图等布尔值)。在 Python 中“前向填充”(从左到右,或从第 0 个索引到第 n 个索引)该数组以使 n 位在每个位都设置为 1 之后设置为 1 的最快方法是什么?

例如,取下面的数组:

[01000100000]

假设 n=2,前向填充数组将是:

[01110111000]

编辑 假设输入是一个包含 10,000 个元素的位数组,其中随机 20% 为真,n=25。这可以表示为一个包含 10,000 个布尔元素的 Python 列表,其中 20% 是 True。这也可以表示为 set,其中包含 0 到 10,000 之间的 2,000 个 int 元素。

编辑 2 首先,以下是使用上述参数的一些示例:

new = set()
new.update(*[range(i, i+25) for i in existing])
# 2.34 ms ± 56.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
new = BitMap()  # This is a pyroaring BitMap
for e in existing:
    new.add_range(e, e+25)
# 461 µs ± 6.02 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

【问题讨论】:

数据类型到底是什么? [0100010000] 很模糊。 可以是任何数据类型。我正在寻找与最终数据类型无关的最快方法。我在问题中提到了几个:list、np.array、bitarray、bitmap、set等 如果不选择实际的数据结构,就不可能回答“最有效”或“最快的方式”。您需要选择一种类型并展示您尝试过的内容。例如,给定一个 bitvec(例如,使用 u64 的底层存储),您将采用与布尔列表截然不同的方法。 不,不应该先选择数据结构。选择的数据结构取决于实际的problem 及其context。所以,问题是:要解决的精确问题是什么。这有什么限制或用例?例如:输入是大还是小?位数是固定的吗?有界吗?等 @JérômeRichard 我编辑了问题以回答您的上述问题。输入相当小,数量可以固定。我同意不应该选择数据结构,因为每个数据结构都有自己的最佳答案。我正在寻找python中可用的全局最优答案。 【参考方案1】:

我已经解决了以下几种数据类型。没有给定时间,您可能希望将语句设置ans 或重构函数以对您有意义的粒度进行时间。

# -*- coding: utf-8 -*-
"""
Created on Sun Dec 19 09:08:56 2021

for: https://***.com/questions/70397220/most-efficient-way-to-forward-fill-a-bit-array

@author: paddy
"""

from random import sample


n = 2  # bits to the right of set bits to also set 
elements = 17
true_percent = 20.0


#%% Using arbitrary precision int
print("\nUsing arbitrary precision int.\n".upper())
from operator import or_
from functools import reduce


# Set some random bits True
bits = sum(1 << r 
           for r in sample(range(elements), int(true_percent/100 * elements)))

# Set n right-adjacent bits.
ans = reduce(or_, (bits >> x for x in range(n+1)), 0)

# Print
print(f"Random bits = bits:0elementsb")
if 1: 
    print()
    for x in range(n+1):
        print(f"              bits >> x:0elementsb")
    print()
print(f"Answer      = ans:0elementsb\n")


#%% Using list.
print("\nUsing list.\n".upper())
from operator import or_
from functools import reduce


bits = [0] * elements
# Set some random bits to 1
for r in sample(range(elements), int(true_percent/100 * elements)):
    bits[r] = 1

# Set n right-adjacent bits.
#   [0]*x is padding bits on the left.
#   zip(*(list1, list2,..)) returns the n'th elements on list1, list2,...
#   int(any(...)) or's them.
ans = [int(any(shifts)) 
       for shifts in zip(*([0]*x + bits for x in range(n+1)))]

# Print
print(f"Random bits = bits")
if 1: 
    print()
    for x in range(n+1):
        print(f"              [0]*x + bits")
    print()
print(f"Answer      = ans\n")


#%% Using numpy.

# Adapt the list solution to use numpy operators on numpy arrays


#%% Using other ordered collections such as str.

# Convert to and from int solution.

样本输出:

USING ARBITRARY PRECISION INT.

Random bits = 01000000010000010

              01000000010000010
              00100000001000001
              00010000000100000

Answer      = 01110000011100011


USING LIST.

Random bits = [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0]

              [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0]
              [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0]
              [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0]

Answer      = [0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0]

【讨论】:

以上是关于前向填充位数组的最有效方法的主要内容,如果未能解决你的问题,请参考以下文章

填充 UITableView 的最有效方法

创建零填充 JavaScript 数组的最有效方法是啥?

Python - 生成填充的最有效方法是啥?

使用 Mongoose 和 GraphQL 从填充模型有条件地返回值的最有效方法?

数据竞赛知识点 | 数值特征的缩放与编码

将 SDF 计算为三角形网格的最有效方法