2017-07-03 127 views
2

我想从列表中随机删除一部分元素而不更改列表的顺序。随机从列表中删除'x'元素

说我有一些数据,我想删除其中1/4:

data = [1,2,3,4,5,6,7,8,9,10] 
n = len(data)/4 

我想我需要一个循环通过数据运行,并删除随机元素“N”次?所以像这样:

for i in xrange(n): 
    random = np.randint(1,len(data)) 
    del data[random] 

我的问题是,这是这样做的最'pythonic'的方式?我的列表将长约5000个元素,我想用不同的'n'值多次执行此操作。

谢谢!

回答

4

您可以使用random.sample这样的:上述

import random 

a = [1,2,3,4,5,6,7,8,9,10] 

no_elements_to_delete = len(a) // 4 
no_elements_to_keep = len(a) - no_elements_to_delete 
b = set(random.sample(a, no_elements_to_keep)) # the `if i in b` on the next line would benefit from b being a set for large lists 
b = [i for i in a if i in b] # you need this to restore the order 
print(len(a)) # 10 
print(b)  # [1, 2, 3, 4, 5, 8, 9, 10] 
print(len(b)) # 8 

有两点需要注意。

  1. 您并未修改原始列表,但可以。
  2. 你是不是真正删除元素,而是保留元素,但它是同一个东西(你只需要调整比率)
  3. 缺点是列表理解的是恢复元素的顺序

正如@koalo在评论中所说的,如果原始列表中的元素不是唯一的,则上述将无法​​正常工作。我可以很容易地解决这个问题,但是我的答案与@ JohnColeman发布的答案完全相同。所以,如果这可能是这种情况,只需使用他的。

+0

谢谢!我实际上想保留'a'中留下的内容而不是删除的内容 –

+0

@RichardHall查看更新 –

+0

如果元素在数组中出现多次,这不起作用! – koalo

4

顺序删除是一个坏主意,因为列表中的删除是O(n)。相反,做这样的事情:

def delete_rand_items(items,n): 
    to_delete = set(random.sample(range(len(items)),n)) 
    return [x for i,x in enumerate(items) if not i in to_delete] 
+0

这也是伟大的,谢谢:) –

0

订单是否有意义? 如果不是你可以这样做:

shuffle(data) 
data=data[:len(data)-n] 
0

我建议使用numpy的索引作为

import numpy as np 
data = np.array([1,2,3,4,5,6,7,8,9,10]) 
n = len(data)/4 
indices = sorted(np.random.choice(len(data),len(data)-n,replace=False)) 
result = data[indices]