> [(i, j) for i in range(1, 4) for j in range(i + 1, 4)]
[(1, 2), (1, 3), (2, 3)]
Более общий код, но на хаскеле.
Идея такая:
Для каждого элемента списка получаем n-1 сочетания из всех, что идут после него, и добавляем сам элемент.
comb ∷ Int → [a] → [[a]]
comb 0 _ = [[]] -- из нуля элементов можно составить только пустой список
comb n [] = [] -- из пустого списка нельзя составить ничего
comb n lst = do -- списочная монада, работает как вложенные for
-- tails для [1,2,3] вернёт [[1,2,3], [2,3], [3], []], т.е. все возможные хвосты
-- мы перебираем все хвосты, кроме последнего пустого
-- и дербаним его на голову l и остаток ls
(l:ls) ← filter (not ∘ null) $ tails lst
-- перебираем сочетания из n - 1 элементов от ls
ls' ← comb (n - 1) ls
-- и присобачиваем l к каждому
return (l:ls')