python – 随机拆分列表,将原始订单保留在新列表中
我很难制定我的问题所以我只是举例说明.
x = ['abc','c','w','t','3'] a,b = random_split(x,3) # first list should be length 3 # e.g. a => ['abc','t'] # e.g. b => ['c','3'] 是否有一种简单的方法可以将列表拆分为两个随机样本,同时保持原始排序? 编辑:我知道我可以使用random.sample然后重新排序,但我希望有一个简单,简单的单行方法. 编辑2:这是另一种解决方案,看看你是否可以改进它: def random_split(l,a_size): a,b = [],[] m = len(l) which = ([a] * a_size) + ([b] * (m - a_size)) random.shuffle(which) for array,sample in zip(which,l): array.append(sample) return a,b 编辑3:我对避免排序的担心是在最好的情况下它是O(N * log(N)).应该可以得到一个可以扩展O(N)的函数.不幸的是,到目前为止发布的解决方案都没有实际达到O(N).虽然经过一番思考后我找到了一个可行的,并且与@ PedroWerneck的性能答案相当.虽然,我不是百分百肯定这是真正的随机. def random_split(items,size): n = len(items) a,[] for item in items: if size > 0 and random.random() < float(size)/n: b.append(item) size -= 1 else: a.append(item) n -= 1 return a,b 解决方法
我相信在拆分后不可能进行限制和排序,同时保持随机性的方式比采样和重新排序更简单.
如果没有限制,那么RNG可以通过遍历列表并随机选择将值发送到的目的地列表来随机选择: >>> import random >>> x = range(20) >>> a = [] >>> b = [] >>> for v in x: ... random.choice((a,b)).append(v) ... >>> a [0,2,3,4,6,7,10,12,15,17] >>> b [1,5,8,9,11,13,14,16,18,19] 如果您可以处理某些偏差,则可以在达到限制时停止附加到第一个列表,并仍使用上述解决方案.如果您将处理示例中的小列表,那么在您获得第一个列表长度之前重试它应该不是什么大问题. 如果您希望它非常随机并且能够限制第一个列表大小,那么您将不得不放弃并重新排序至少一个列表.我认为最接近单线程实现的是: >>> x = range(20) >>> b = x[:] >>> a = sorted([b.pop(b.index(random.choice(b))) for n in xrange(limit)]) >>> a [0,1,17] >>> b [2,19] 你必须对a进行排序,但是b保留了顺序. 编辑 现在,你真的必须不惜一切代价避免重新排序吗?发布了许多简洁的解决方案,您的第二个解决方案非常好,但没有一个比以下更简单,更容易和更短: def random_split(items,size): sample = set(random.sample(items,size)) return sorted(sample),sorted(set(items) - sample) 即使考虑到两种排序操作,我认为为了简单和高效,很难击败那种.考虑优化的Python的Timsort是如何优化的,以及大多数其他方法如何为每个列表至少迭代n个项目一次. 如果你真的必须避免重新排序,我想这个也可以工作,非常简单,但迭代两次: def random_split(items,size)) a = [x for x in items if x in sample] b = [x for x in items if x not in sample] return a,b 这与Hexparrot的解决方案基本相同,发送者建议使用set(样本)进行比较O(1),并删除冗余索引样本并枚举调用.如果只处理可散列对象,则不需要它. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |