从列表中删除第n个元素的更好方法

时间:2018-07-31 09:05:11

标签: python python-3.x

我有1000个元素的列表。现在,我需要从该列表中删除1st,2nd,4th,8th,16th,32nd等元素。这是我的解决方法

i = 0
while pow(2,i) < len(arr):
    del arr[pow(2,i) - 1 - i]
    i += 1

但是我认为这似乎是一些不好的代码。有没有更优雅的方法来获得相同的结果?

4 个答案:

答案 0 :(得分:1)

您需要撤消您的迭代;从最高值开始删除幂。从大于列表长度的下一个最大幂2开始,然后从那里向下移:

i = 2 ** len(arr).bit_length()  # next higher power-of-two > len
while i > 1:
    i >>= 1
    del arr[i - 1]  # 4th index is 3, 8th index is 7, etc.

另一种选择:您可以生成一个新列表,而不是就地从列表中删除:

[v for i, v in enumerate(arr, 1) if i & (i - 1)]

这利用了一个事实,即2的幂仅设置了一位。如果用数字-1掩盖,则为零。

演示:

>>> arr = list(range(1, 33))  # 6 values to remove, 1, 2, 4, 8, 16 and 32
>>> arr
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]
>>> len(arr)
32
>>> [v for i, v in enumerate(arr, 1) if i & (i - 1)]
[3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
>>> i = 2 ** len(arr).bit_length()  # highest power-of-two >= len
>>> while i > 1:
...     i >>= 1
...     del arr[i - 1]  # 4th index is 3, 8th index is 7, etc.
...
>>> arr
[3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
>>> arr == [v for i, v in enumerate(range(1, 33), 1) if i & (i - 1)]
True
>>> len(arr)
26

答案 1 :(得分:1)

使用numpy.delete

的解决方案

从数组开始,以大小随机生成,例如1000

import numpy as np
a = np.random.randint(100, size=(1000))

我们首先确定数组大小内的2的最大幂:

max_power = np.ceil(np.log2(len(a)))

此示例中max_power的内容为10

现在我们可以创建一个具有2的幂的数组,代表要删除的索引:

exponents = np.arange(1, max_power)
indices = np.power(np.full(len(exponents), 2), exponents).astype(np.int)

索引数组包含array([ 2, 4, 8, 16, 32, 64, 128, 256, 512])

现在,我们可以继续删除这些索引:

result = np.delete(a, indices)

时间比较:numpy和列表理解

%timeit np.delete(a, indices)
>>> 35.1 µs ± 2.07 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%timeit [a[i] for i in range(len(a)) if i+1 not in powers_to_remove]
>>> 372 µs ± 25.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

答案 2 :(得分:0)

那又怎么样:

/* generating a random array from a source array, algorithm */

function createRandomArray(srcArray, amount) {
    var rndArray = []; // random array

    while (rndArray.length < amount) { // how many random items?

        // generating a random index
        const random_index = Math.floor(Math.random() * srcArray.length);

        // if random array doesn't have random index then...
        if (!rndArray.includes(random_index)) {
            // push the current item from source array with random inex
            rndArray.push(srcArray[random_index]);

            // then remove the selected item from source array with random inex
            srcArray.splice(random_index, 1);
        }
    }
    return rndArray; // the output of this function is a an array with random items
}


const sourceArray = [1,2,3,4,5,6,7,8,9,0];
print(createRandomArray(sourceArray, 5));

// output [6, 1, 8, 2, 7]

答案 3 :(得分:0)

您还可以反向迭代2的幂:

mx = (len(arr) - 1).bit_length() - 1

for idx in (1 << i for i in range(mx, -1, -1)):
    del arr[idx]

mx = (len(arr) - 1).bit_length() - 1是可以删除的2的最高指数。

1 << i只是pow(2, i)(整数)。