我想详尽地分析用于对小型数组进行排序的子例程,并需要一种方法来生成特定长度的所有唯一排序的数组。 在Python中,该列表将以非负整数作为元素,并且在可能的情况下最好使用最小整数。例如,N = 3:
Drawable drawable = RoundedBitmapDrawableFactory.create(context.getResources(), bitmap);
//set imageview XML - call your image view
imageView.setImageDrawable(drawable);
[[0,0,0],
[0,0,1],
[0,1,0],
[0,1,1],
[0,1,2],
[0,2,1],
[1,0,0],
[1,0,1],
[1,0,2],
[1,1,0],
[1,2,0],
[2,0,1],
[2,1,0]]
和[1,1,1]
不属于上面的列表,因为[2,2,0]
和[0,0,0]
在使用较小的整数时分别具有相同的相对顺序。
答案 0 :(得分:2)
这是以下各项的组合:(a)查找列表[k_1, ..., k_n]
,以使每个k_i
等于k_(i-1)
或k_(i-1)+1
,以及(b)查找这些列表的唯一排列列表。
第一个可以使用递归函数完成:
def combinations(n, k=0):
if n > 1:
yield from ([k] + res for i in (0, 1)
for res in combinations(n-1, k+i))
else:
yield [k]
对于具有n
个元素的列表,将有2^(n-1)
个这样的组合:
>>> list(combinations(2))
[[0, 0], [0, 1]]
>>> list(combinations(3))
[[0, 0, 0], [0, 0, 1], [0, 1, 1], [0, 1, 2]]
>>> list(combinations(4))
[[0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 1], [0, 0, 1, 2], [0, 1, 1, 1], [0, 1, 1, 2], [0, 1, 2, 2], [0, 1, 2, 3]]
使用itertools.permutations
组合并过滤出重复项以得到最终结果:
import itertools
def all_combinations(n):
return (x for combs in combinations(n)
for x in set(itertools.permutations(combs)))
示例:
>>> list(all_combinations(3))
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0), (0, 1, 1), (1, 0, 1), (1, 1, 0), (0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
>>> sum(1 for _ in all_combinations(4))
75
>>> sum(1 for _ in all_combinations(5))
541
注意:生成 all n!
排列,然后过滤重复项,即使对于n
稍大的值,也可能非常浪费。有一些更聪明的方法可以生成仅可用于代替itertools.permutations
的唯一排列,例如,参见here或here。
答案 1 :(得分:1)
您可以遍历该范围的笛卡尔积,对于每个元素,请使用相对顺序作为键,并将该对(相对顺序,元组)存储在字典中,最后返回已排序的:
def uniquely_ordered_list(n=3):
def key(o):
relative = ['equal'] + ['less' if a < b else ('greater' if a > b else 'equal') for a, b in product(o, repeat=2)]
return tuple(relative)
found = {}
for ordering in product(range(n), repeat=n):
if key(ordering) not in found:
found[key(ordering)] = ordering
return sorted(found.values())
输出
(0, 0, 0)
(0, 0, 1)
(0, 1, 0)
(0, 1, 1)
(0, 1, 2)
(0, 2, 1)
(1, 0, 0)
(1, 0, 1)
(1, 0, 2)
(1, 1, 0)
(1, 2, 0)
(2, 0, 1)
(2, 1, 0)
更新
如@tobias_k所建议,您可以将以下函数用作键:
def key(o):
sign = lambda x: x / abs(x) if x else x
return tuple([0] + [sign(a - b) for a, b in product(o, repeat=2)])
答案 2 :(得分:1)
这是另一种解决方案:
import numpy as np
from itertools import product, combinations
def rord(lst):
''' Maps the relative order of a list 'lst' to a unique string of 0, 1, and 2.
Relative order is computed by converting the list 'sgns' of all
the values sgn(lst[i]-lst[j])+1, for i<j, i,j = 0,..., n-1,
to a string.
E.g. the lists [0, 0, 1], [0, 0, 2] and [1, 1, 2] have the same rord = '100'
because lst[0] = lst[1], lst[0] < lst[1], lst[1] < lst[2] for all
of them, so sgns = [1, 0, 0]
'''
sgns = np.sign([tup[0]-tup[1] for tup in combinations(lst, 2)]) + 1
return ''.join(str(e) for e in sgns) # return sgns.tostring() is faster
def uniq_rord_lst(n):
'''Returns n-length sequences of integers 0,... n-1, with unique relative
order. E.g. for n=2 returns [(0, 0), (0, 1), (1, 0)].
'''
seen_ro = set()
result = []
for comb in product(range(n), repeat=n):
ro = rord(comb)
if ro not in seen_ro:
seen_ro.add(ro)
result.append(comb)
return result
示例:
>>> uniq_rord_lst(2)
[(0, 0), (0, 1), (1, 0)]
>>> uniq_rord_lst(3)
[(0, 0, 0),
(0, 0, 1),
(0, 1, 0),
(0, 1, 1),
(0, 1, 2),
(0, 2, 1),
(1, 0, 0),
(1, 0, 1),
(1, 0, 2),
(1, 1, 0),
(1, 2, 0),
(2, 0, 1),
(2, 1, 0)]
更新:更快的
def uniq_rord_lst(n):
seen_ro = set()
result = []
for comb in product(range(n), repeat=n):
ro = tuple(sorted(comb).index(x) for x in comb)
if ro not in seen_ro:
seen_ro.add(ro)
result.append(comb)
return result