Random split list, keeping the original order in new lists
<p>I am having a hard time formulating my question so I'll just show by example.</p>

<pre><code>x = ['abc', 'c', 'w', 't', '3']
a, b = random_split(x, 3)      # first list should be length 3
# e.g. a =&gt; ['abc', 'w', 't']
# e.g. b =&gt; ['c', '3']
</code></pre>

<p>Is there an easy way of splitting a list into two random samples while maintaining the original ordering?</p>

<hr>

<p><strong>Edit:</strong> I know that I could use random.sample and then reorder, but I was hoping for an easy, simple, one line method.</p>

<p><strong>Edit 2:</strong> Here's another solution, see if you can improve it:</p>

<pre><code>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
</code></pre>

<p><strong>Edit 3:</strong> My concern in avoiding sorting was that in the best case scenario it is <code>O(N*log(N))</code>. It should be possible to get a function that scales <code>O(N)</code> Unfortunately, none of the solutions posted so far actually achieve <code>O(N)</code> Though, after a little thought I found one that works and is comparable to @PedroWerneck's answer in performance. Though, I'm not 100% sure that is truly random.</p>

<pre><code>def random_split(items, size):
  n = len(items)
  a, b = [], []
  for item in items:
    if size &gt; 0 and random.random() &lt; float(size)/n:
      b.append(item)
      size -= 1
    else:
      a.append(item)

    n -= 1

  return a, b
</code></pre>
