【发布时间】:2011-02-06 06:46:05
【问题描述】:
我有一个数组:
array([[ 4, 10],
[ 4, 2],
[ 0, 7],
[ 5, 11],
[ 6, 8],
[ 3, 6],
[ 9, 7],
[ 2, 11],
[ 9, 5],
[ 8, 1]])
我想要一种方法来对值对进行排序,以便尽可能多的成对 2 元素集具有共同的值。这是所需有序数组的示例:
array([[ 4, 10],
[ 4, 2],
[ 2, 11],
[ 5, 11],
[ 9, 5],
[ 9, 7],
[ 0, 7], #note the gap here:
[ 8, 1],
[ 6, 8],
[ 3, 6]])
关于这些数组有几个条件成立。没有重复的对(即:如果 [0,1] 已经存在,则 [1,0] 或 [0,1] 将出现在数组的其他位置)。没有一对具有相同的值(即:[1,1] 将不存在)。没有一对将有两个以上的匹配项(iow:整个数组中没有任何值存在超过两次。)但是一对可以有少至零个匹配项(请注意在上面的数组中没有匹配项的间隙)。
显然,我可以创建数组的每个排列,但这似乎很野蛮。我认为可能有某种方法可以切割甲板并以合乎逻辑的方式重新堆叠,这样它就可以在少量切割中进行分类。但在我走这条路之前,我想: 1) 确保没有 numpy 或 collections 函数已经这样做了。 2) 知道使用 numpy .sort() (或类似的)没有棘手的天才方法来做到这一点。 3)找出这是否是一个常见的任务,并且有算法可以做到这一点。 (“哦,这就是 Blumen-Funke 算法!”)
这里有一些代码可以生成混洗的测试数组并检查排序的数组:
def shuffled(N=12, ans=1):
'''returns is now the unsorted test array'''
r = range(N)
random.shuffle(r)
l = []
for i in range(N):
l.append((r[i-1], r[i]))
random.shuffle(l)
return np.array(l)[ans+1:]
# step 2: ???
def test_ordered(a):
'''checks if generated array has been sorted'''
c0 = a[1:,0]==a[:-1,0]
c1 = a[1:,0]==a[:-1,1]
c2 = a[1:,1]==a[:-1,0]
c3 = a[1:,1]==a[:-1,1]
cond = c0+c1+c2+c3
ans = sum(numpy.logical_not(cond))
# when sorted this should return the same number input into
# shuffled() as 'ans':
return ans
(这是一个主观问题吗?有人警告我是。)
结果:
非常感谢您的帮助。 Sven 的解决方案比 Paul 的解决方案快 20% 左右,而且令人高兴的是,它们都在线性时间内运行,Doug 的回答并没有解决问题。性能对输入数据中“中断”或“间隙”的数量存在很高但也很大程度上是线性的依赖关系。见下图。 10,000 量级轴是 N。0.5 轴是中断的百分比。 z 轴是以秒为单位的性能。
再次感谢!
【问题讨论】:
-
这并不是真正的“排序”,而是想出“多米诺骨牌”对的[最长]运行。使用适当的算法。排序更经常然后不需要在排序输入中的任何两个值之间定义独立排序。然而,上面请求的排序依赖于其他值。我不确定 Blumen-Funke 算法,但这可以使用pigeon-hole principle 解决——快乐编码。
-
不是主观的。科学话语中对“最佳”的定义非常狭窄,在这种情况下,这意味着“我想要一种对其进行排序的方法,以便尽可能多的成对 2 元素集具有共同值。”
-
OTH,我同意@pst,我认为您的输出中的任何两对都没有自然排序,因此您可能需要改写您的问题。您正在寻找类似一组分组的东西,对吗?还是这里有我看不到的订单?
-
您的输入是一个无向图 - 每对都是一条不同的边。您正在寻找一种方法来尽可能少地“举起笔”来绘制它。不知道解决方案,但我想贪婪地消耗欧拉行走是一个好的开始......
-
@Wong 由于数据的限制,没有pair会有两个以上的匹配,它产生了一组1D图,在某种意义上是有顺序的(倒序是等价的)跨度>