2016-03-04 2 views
4

У меня есть список идентификаторов, представляющих пользователей, и я пишу функцию, чтобы превратить этот список идентификаторов в расписание пользовательских сопоставлений (пар) :Сортировка списка кортежей, так что группировка по ключу не нужна

ids = [1, 2, 3, 4] 

график, связанные с этим будет выглядеть так:

week 1: (1, 2), (3, 4) 
week 2: (1, 3), (2, 4) 
week 3: (1, 4), (2, 3) 
week 4: (1, 2), (3, 4) [repeat of week 1] 

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

ids = [1,2,3,4] 
matchups = [] 

#generate all the combinations of matchups 
for subset in itertools.combinations(ids,2): 
    matchups.append(subset) 

Это возвращает все потенциальные пары как список кортежей - отлично! В этом суть того, что я ищу. Моя проблема теперь выясняет, как превратить это во что-то полезное. Например, приведенный выше код возвращает этот список для matchups:

[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] 

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

С этой целью я пытался выяснить, как сортировать список кортежей на основе элементов, которые являются не равным. Метод sorted() имеет множество полезных реализаций такого типа ситуаций, но я могу получить результаты только в том случае, если результаты сгруппированы, например, выше.

Я хотел бы найти применение sorted(), который будет возвращать следующий, почти как анти-рода:

[(1, 2), (3, 4), (1, 3), (2, 4), (1, 4), (2, 3)] 

Есть ли способ использовать lambda для этого?

EDIT: Я только что понял, что 1-й элемент должен быть сопряжен с 6-м, 2-м, 5-м и 3-м с 4-м. Я не знаю, распространяется ли это на общий случай, но я ожидаю, что это возможно, потому что я предпринял другие шаги, чтобы гарантировать, что всегда есть четное число идентификаторов.

Теперь я уверен, что есть способ интерполировать список, чтобы достичь этого.

EDIT2: Похоже, предыдущая догадка не была правильной - она ​​не работает с 6 идентификаторами, и, вероятно, все, что за ее пределами, тоже потерпит неудачу. Я вернусь к тому, чтобы выяснить, есть ли способ разгона вместо сортировки на основе ключа

+0

'random.shuffle' является анти-рода :) –

+0

Очень true- я понял, моя терминология не была великорусского это больше, как мне нужно, чтобы обеспечить уникальность, а не группировка по ключу. – dkhaupt

+0

Почему вы не можете использовать цикл for? Порядок второго списка - это просто '0 5 1 4 2 3'. –

ответ

1

Это им Алгоритм турнира с круговым движением википедии.

x = range(1, 11) #10 players 

def round_robin(someIds): 
    someIds = someIds[::2] + someIds[1::2] 
    first, someIds = [someIds[0]], someIds[1:] 
    n = len(someIds) 
    for i in range(n): 
     top = someIds[:n/2] 
     bottom = someIds[n/2:] 
     yield zip(first+top, bottom) 
     someIds = someIds[-1:] + someIds[:-1] 


for thing in round_robin(x): 
    print thing 

Выход

[(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)] 
[(1, 3), (4, 5), (6, 7), (8, 9), (10, 2)] 
[(1, 4), (5, 6), (7, 8), (9, 10), (2, 3)] 
[(1, 5), (6, 7), (8, 9), (10, 2), (3, 4)] 
[(1, 6), (7, 8), (9, 10), (2, 3), (4, 5)] 
[(1, 7), (8, 9), (10, 2), (3, 4), (5, 6)] 
[(1, 8), (9, 10), (2, 3), (4, 5), (6, 7)] 
[(1, 9), (10, 2), (3, 4), (5, 6), (7, 8)] 
[(1, 10), (2, 3), (4, 5), (6, 7), (8, 9)] 
+0

Это работает, спасибо.Вы и @Prune были правы - я должен был просто заглянуть в это от get go – dkhaupt

+1

изменил его так, чтобы он печатал в том порядке, в котором вы искали –

+0

Еще раз спасибо, поэтому я использовал pythonfiddle.com для работы над этим, но когда я пытаюсь запустить его в своей домашней среде (Python 3.4), я получаю следующую ошибку: 'TypeError: индексы среза должны быть целыми или None или иметь __index__method'. Любая идея, почему это может быть? – dkhaupt

1

Я считаю, что вы ищете канонический алгоритм планирования round-robin.

Список ваших игроков в любом порядке найти удобный, в два ряда:

1 2 3 4 
5 6 7 8 

Ваш первый круглый спариваний являются 1-5, 2-6, 3-7, 4-8. В течение последующих недель поворачивайте все, кроме позиции # 1: верхняя строка сдвигается влево, нижняя строка сдвигается вправо; те, которые падают с конца (2 и 8) двигаться вверх/вниз на пустое место:

1 3 4 8 
2 5 6 7 

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

+0

Я ценю ваш ответ, но есть ли преимущество в том, чтобы объединить все комбинации в моем посте? Разве они разные? У меня только 4 ID, но я думаю, что конечный результат может быть таким же. Несмотря на это, я доволен выходом кортежей из метода 'комбинация()', я думаю, что это больше вопрос сортировки/списка. – dkhaupt

+0

Круговые соединения легко обобщаются на любое количество идентификаторов и гарантируют, что каждый идентификатор имеет пару в каждой группе из N/2 пар. Из вашего описания я подумал, что это был пункт вашего * анти-сортировки *. – Prune

+0

Я полагаю, что это так, но в то же время я считаю, что вывод метода 'комбинация() дает мне то, что делает круговой робот. Есть ли какой-либо пакет, реализующий round-robin? – dkhaupt

1

Потенциально унииоматическое решение, но оно работает. Может быть, кто-то может сделать его более питоническим? : D

def antisort(x): 
    if len(x) > 0: 
     return [x[0]] + antisort(x[-1:0:-1]) 
    else: 
     return [] 

>>> antisort([(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]) 
[(1, 2), (3, 4), (1, 3), (2, 4), (1, 4), (2, 3)] 

Этот кусочек нотация просто принимает все после первого элемента и меняет его:

x[-1:0:-1] 
+0

Спасибо за ваш ответ - похоже, что у меня было правдоподобное недоверие, потому что это работает для 4 элементов, но не 6 – dkhaupt

1

Это то, что я имел в виду мой комментарий:

a = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] 
new = [] 

i, j = len(a)-1, 0 

for n in range(i+1): 
    if n % 2: 
     new.append(a[i]) 
     i -= 1 
    else: 
     new.append(a[j]) 
     j += 1 

print(new) 

Выход:

[(1, 2), (3, 4), (1, 3), (2, 4), (1, 4), (2, 3)] 
+0

Это работает с 4 элементами, но не с большим количеством - кажется, t правильно. Но спасибо – dkhaupt

+0

@dkhaupt Почему 4? Список состоит из 6 элементов. Или вы имеете в виду недели? –

+0

Да - вывод кортежа имеет 6 элементов, извините - я имел в виду список идентификаторов, который генерирует вывод кортежа. С 4 идентификаторами это работает, но когда я увеличиваю до 6 идентификаторов, он больше не работает – dkhaupt

Смежные вопросы