Эффективно пара случайных элементов списка - PullRequest
0 голосов
/ 15 мая 2019

У меня есть список n элементов, которые говорят: foo = ['a', 'b', 'c', 'd', 'e'] Я хотел бы случайным образом соединить элементы этого списка, чтобы получить, например: bar = [['a', 'c'], ['b', 'e']] где последний элемент будет отброшен, если длина списка не четная.

Сейчас у меня есть функция грубой силы:

def rnd_pair(foo):
    while len(foo) > 1:
         pair_idxs = np.sort(np.random.choice(range(len(foo)), 2, replace=False))
         el_pair = [foo.pop(pair_idxs[0]), foo.pop(pair_idxs[1] - 1)]

         el_pairs.append(el_pair)

Это не очень эффективно. Также я не люблю менять список на месте. Есть идеи по более эффективному способу? Заранее спасибо.

Ответы [ 4 ]

3 голосов
/ 15 мая 2019

Я бы сказал, что это самый питонический способ справиться с этим:

foo = ['a', 'b', 'c', 'd', 'e', 'f']
random.shuffle(foo)
length = len(foo)//2
result = list(zip(foo[:length], foo[length:]))

Zip объединит элементы в одном и том же индексе нескольких списков и остановится, когда в одном списке закончатся элементы. Итак, вы собираетесь перетасовать список и взять первую и вторую половину списка, а затем комбинировать их поэлементно до тех пор, пока у более короткого не останется элементов.

Изменить: вы сказали, что вы заинтересованы в исполнении различных способов обработки. Я сделал функцию для каждого из уникальных ответов здесь и рассчитал их время:

def a(foo):
    random.shuffle(foo)
    length = len(foo)//2
    return list(zip(foo[:length], foo[length:]))

def b(foo):
    random.shuffle(foo)
    return [[foo[i], foo[i+1]] for i in range(0, len(foo)-(len(foo)%2), 2)]

def c(foo):
    np.random.shuffle(foo)
    return foo[:len(foo)-(len(foo)%2)].reshape(2,-1)

def d(foo):
    result = []
    for i in range(1, len(foo), 2):
        result.append([foo[i-1], foo[i]])
    return result

def e(foo):
    el_pairs = []
    while len(foo) > 1:
         pair_idxs = np.sort(np.random.choice(range(len(foo)), 2, replace=False))
         el_pair = [foo.pop(pair_idxs[0]), foo.pop(pair_idxs[1] - 1)]
         el_pairs.append(el_pair)
    return el_pairs

def f(foo):
    random.shuffle(foo)
    length = len(foo)//2
    return zip(foo[:length], foo[length:])

почтовый индекс без списка:

%timeit f(foo)
3.96 µs ± 12.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Почтовый индекс:

%timeit a(foo)
4.36 µs ± 156 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Понимание списка:

%timeit b(foo)
4.38 µs ± 22.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Для цикла:

%timeit d(foo)
812 ns ± 5.68 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

Оригинал:

%timeit e(foo)
154 ns ± 1.11 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

Ответ на вопрос, который мне дали, не закончился.

1 голос
/ 15 мая 2019
import random
import string

def random_pairs(x):
  random.shuffle(x)
  return zip(*(2 * [iter(x)]))

# Shuffling in place.
array = list(string.lowercase) # a-z
print list(random_pairs(array))

# Not Shuffling in place.
array = list(string.uppercase) # A-Z
pairs = random_pairs(range(len(array)))
print map(lambda pair: map (lambda i: array[i], pair), pairs)
1 голос
/ 15 мая 2019

Попробуйте это:

from random import shuffle

foo = ['a', 'b', 'c', 'd', 'e']
shuffle(foo)

result = []
for i in range(1, len(foo), 2):
  result.append([foo[i-1], foo[i]])

print(result)
1 голос
/ 15 мая 2019
>>> import random
>>> foo = ['a', 'b', 'c', 'd', 'e']
>>> random.shuffle(foo)
>>> bar = list(zip(foo[::2], foo[1::2]))
>>> bar
[('e', 'd'), ('c', 'a')]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...