加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

python – 随机拆分列表,将原始订单保留在新列表中

发布时间:2020-12-20 12:28:09 所属栏目: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'] 是否有一种简单的方法可以将列表拆分为两个随机样本,同时保持原始排序? 编辑:我
我很难制定我的问题所以我只是举例说明.

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),并删除冗余索引样本并枚举调用.如果只处理可散列对象,则不需要它.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读