Генерування перестановок з повтореннями


84

Я знаю про itertools, але, здається, він може генерувати лише перестановки без повторень.

Наприклад, я хотів би створити всі можливі кидки для 2 кубиків. Тож мені потрібні всі перестановки розміру 2 із [1, 2, 3, 4, 5, 6], включаючи повторення: (1, 1), (1, 2), (2, 1) ... тощо

Якщо можливо, я не хочу реалізовувати це з нуля

Відповіді:


144

Ви шукаєте декартовий продукт .

В математиці декартовий твір (або набір творів) є безпосереднім добутком двох множин.

У вашому випадку це буде {1, 2, 3, 4, 5, 6}x {1, 2, 3, 4, 5, 6}. itertoolsможе вам там допомогти:

import itertools
x = [1, 2, 3, 4, 5, 6]
[p for p in itertools.product(x, repeat=2)]
[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 1), (2, 2), (2, 3), 
 (2, 4), (2, 5), (2, 6), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), 
 (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (5, 1), (5, 2), (5, 3), 
 (5, 4), (5, 5), (5, 6), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6)]

Щоб отримати випадковий кидок кісток ( абсолютно неефективним способом ):

import random
random.choice([p for p in itertools.product(x, repeat=2)])
(6, 3)

8
Це надзвичайно неефективний спосіб отримати 2 кисті кубиків ... Два дзвінки на random.randintбули б простішими та ефективнішими.
Eric O Lebigot

Випадкові кидки кубиків будуть набагато швидшими, якщо ви не згенеруєте всіх можливих пар: [random.randint (1,6) for i in xrange (2)]
liori

13
Я насправді не намагався генерувати випадкові рулони, а лише перерахувати всі можливі ролики.
Bwmat


7

У python 2.7 і 3.1 є itertools.combinations_with_replacementфункція:

>>> list(itertools.combinations_with_replacement([1, 2, 3, 4, 5, 6], 2))
[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 2), (2, 3), (2, 4), 
 (2, 5), (2, 6), (3, 3), (3, 4), (3, 5), (3, 6), (4, 4), (4, 5), (4, 6),
 (5, 5), (5, 6), (6, 6)]

12
Це рішення втрачає на комбінаціях (2, 1), (3, 2), (3, 1)і подібне ... В цілому вона виходить з усіх комбінацій , де другий рулон нижче , ніж перший.
Холрой,

1

У цьому випадку розуміння списку особливо не потрібно.

Дано

import itertools as it


seq = range(1, 7)
r = 2

Код

list(it.product(seq, repeat=r))

Деталі

Неочевидно, що декартовий добуток може генерувати підмножини перестановок. Однак з цього випливає, що:

  • із заміною: вивести всі перестановки n r черезproduct
  • без заміни: фільтр від останнього

Перестановки із заміною, n r

[x for x in it.product(seq, repeat=r)]

Перестановки без заміни, n!

[x for x in it.product(seq, repeat=r) if len(set(x)) == r]
# Equivalent
list(it.permutations(seq, r))  

Отже, усі комбінаторні функції можуть бути реалізовані з product:

  • combinations_with_replacement реалізується з product
  • combinationsреалізований з permutations, який може бути реалізований за допомогою product(див. вище)

-1

Я думаю, що я знайшов рішення, використовуючи лише lambdas, mapі reduce.

product_function = lambda n: reduce(lambda x, y: x+y, map(lambda i: list(map(lambda j: (i, j), np.arange(n))), np.arange(n)), [])

По суті, я відображаю першу лямбда-функцію, яка задає рядок, ітерацію стовпців

list(map(lambda j: (i, j), np.arange(n)))

тоді це використовується як вихід нової лямбда-функції

lambda i:list(map(lambda j: (i, j), np.arange(n)))

який відображається у всіх можливих рядках

map(lambda i: list(map(lambda j: (i, j), np.arange(n))), np.arange(m))

а потім ми зменшуємо всі отримані списки в один.

навіть краще

Також можна використовувати два різних числа.

prod= lambda n, m: reduce(lambda x, y: x+y, map(lambda i: list(map(lambda j: (i, j), np.arange(m))), np.arange(n)), [])

-2

По-перше, вам спочатку потрібно перетворити генератор, повернутий itertools.permutations (list), у список. Потім, по-друге, ви можете використовувати set () для видалення дублікатів Щось, як показано нижче:

def permutate(a_list):
    import itertools
    return set(list(itertools.permutations(a_list)))

1
Сюди не входять дублікати.
Бьорн Ліндквіст,

1
OP прямо вимагає дублікатів
Levi Lesches
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.