Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Randomly Interleave 2 Arrays In Python

Suppose I have two arrays:

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

I want to interleave these two arrays to a variable 'c' (note 'a' and 'b' aren't necessarily of equal length) but I don't want them interleaved in a deterministic way. In short, it isn't enough to just zip these two arrays. I don't want:

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

Instead, I want something random like:

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

Also notice that the order of 'a' and 'b' are preserved in the resulting array, 'c'.

The current solution I have requires a for loop and some random number generation. I don't like it and I'm hoping someone can point me to a better solution.

# resulting array
c = []

# this tells us the ratio of elements to place in c. if there are more elements 
# in 'a' this ratio will be larger and as we iterate over elements, we will place
# more elements from 'a' into 'c'.
ratio = float(len(a)) / float(len(a) + len(b))

while a and b:
    which_list = random.random()
    if which_list < ratio:
        c.append(a.pop(0))
    else:
        c.append(b.pop(0))

# tack on any extra elements to the end
if a:
    c += a
elif b:
    c += b
like image 507
salil Avatar asked May 17 '12 23:05

salil


People also ask

How do you interlace two lists in Python?

chain() + zip() zip() can be used to link both the lists and then chain() can used to perform the alternate append of the elements as desired. This is the most efficient method to perform this task.

How to add two arrays in one array?

In order to combine (concatenate) two arrays, we find its length stored in aLen and bLen respectively. Then, we create a new integer array result with length aLen + bLen . Now, in order to combine both, we copy each element in both arrays to result by using arraycopy() function.

What is interleaved array?

"Interleaved" means that multiple attributes, possibly of different types, (e.g., position, normal, uv, color) are packed into a single array buffer.


1 Answers

edit: I think this recent one is best:

a = [1, 2, 3, 4]
b = [5, 6, 7, 8, 9]
c = [x.pop(0) for x in random.sample([a]*len(a) + [b]*len(b), len(a)+len(b))]

Or more efficiently:

c = map(next, random.sample([iter(a)]*len(a) + [iter(b)]*len(b), len(a)+len(b)))

Note that the first method above modifies the original lists (as your code did) while the second method does not. On Python 3.x you would need to do list(map(...)) since map returns an iterator.

original answer below:

Here is an option that saves a few lines:

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

c = []
tmp = [a]*len(a) + [b]*len(b)
while a and b:
    c.append(random.choice(tmp).pop(0))

c += a + b

Here is another option, but it will only work if you know that all of your elements are not falsy (no 0, '', None, False, or empty sequences):

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

ratio = float(len(a)) / float(len(a) + len(b))
c = [(not a and b.pop(0)) or (not b and a.pop(0)) or
     (random.random() < ratio and b.pop(0)) or a.pop(0)
     for _ in range(len(a) + len(b))]
like image 134
Andrew Clark Avatar answered Oct 23 '22 06:10

Andrew Clark