【发布时间】:2013-09-16 10:39:07
【问题描述】:
所以,
问题
第一种情况
我有一个包含一些值的数组 - 首先,让它们都是字符串(或者可以简单地视为字符串)。示例:
$rgData = ['foo', 'feo', 'bar', 'baz', 'bee'];
现在,我想从中创建唯一数组,其中两个项目之间的Levenshtein distance 小于 2。即如果levenshtein($x, $y) < 2,项目$x 和$y 被视为相等。例如,foo 和 feo 相等,bar 和 baz - 但不是 bar 和 bee。
第二种情况
我有一个数组,每个点的坐标为[x, y],例如:
$rgData = [[0, 0.1], [-5, 4.5], [0, 0.5], [-5.5, 4.5]];
现在,我想从中创建唯一的数组,其中两点之间的距离小于 1。即如果pow((pow($x[0]-$y[0], 2) + pow($x[1]-$y[1],2)), 0.5)<1 点$x 和$y 被视为相等
很明显,这两种情况都可以通过一些函数来解决,这将类似于标准 PHP array_unique() - 但它接受比较函数来检查项目是否相等。我的问题是关于那个功能的。
我的方法
现在,我有最简单的函数解决方案:
function array_uunique($rgData, $fnCompare=null)
{
if(!isset($fnCompare))
{
return array_unique($rgData);
}
if(!is_callable($fnCompare))
{
return null;
}
if(!count($rgData))
{
return array();
}
$rgResult = array();
foreach($rgData as $mItem)
{
foreach($rgResult as $mTest)
{
if(!call_user_func_array($fnCompare, [$mItem, $mTest]))
{
continue 2;
}
}
$rgResult[]=$mItem;
}
return $rgResult;
}
-它接受回调作为第二个参数,并返回与此比较规则不相等的元素,即对于 levenshtein,所描述的结果将是:
$rgResult = array_uunique(['foo', 'feo', 'bar', 'baz', 'bee'], function($x, $y)
{
return levenshtein($x, $y)>1; //or !levenshtein($x, $y)<2
});
-这将导致
数组(3){ [0]=> 字符串(3)“富” [1]=> 字符串(3)“酒吧” [2]=> 字符串(3)“蜜蜂” }-您可以使用this fiddle 进行测试。
具体说明
如上所述,这是最简单的方式,但它内部包含2个嵌套的依赖循环。因此,这种构造的复杂性将是O(N^2) - 这很可悲 - 并且对我不起作用,特别是如果比较函数操作成本很高 - 因为我将在数据数组中有大量元素(~1E5..1E6至少)。
我的问题是 - 如何改进这一点?可能还有另一种好的算法吗?或者可能是我的代码可以以某种方式改进?
更新(基于下面的好评论):我知道在常见情况下,此类问题会导致transitive function 问题,即xFy = yFz => xFz - 例如,levenshtein() 是不及物。因此,在常见情况中,整个结果将至少取决于项目顺序(但不仅仅是来自它)——现在这对我来说不是问题,因为我确定我的数据顺序和内容(或者,至少,bar 或 baz 是否将通过 levenshtein 比较返回无关紧要)。所以,我的目标是尽量减少比较次数(我认为,比较函数传递或不改变什么都不会改变,因为我想优化甚至重新创建比较算法本身)
【问题讨论】:
-
性能不是您的第一个问题,因为您的比较功能不是transitive,结果取决于您不想要的输入顺序,我认为,请参阅3v4l.org/vQZVg
-
当然不是(并且在常见情况下它不能通过问题的定义传递)。我知道,如果我以这种方式定义我的比较函数,那么结果将至少取决于项目顺序。所以现在这对我来说不是问题
-
@AlmaDoMundo 结果取决于输入顺序,比较方法事先未知,我怀疑您的功能可以“优化”到什么程度:您无法重新排列项目,也无法“猜测”/“预测” " 基于历史的两个项目的距离。
-
@Passerby 但我的问题是关于方法本身 - 即如何最小化比较操作的数量?好的,想象一下比较函数将是传递的——这不会改变我的目标(即获得一个比较次数最少的结果)
-
你说:有一个集合,你想计算它有多少组,其中组表示给定函数 G(a,b)=>T/F 告诉 a,b 在同一个组中.如果对您的输入集没有任何进一步的了解,您需要在最坏的情况下比较 n(n-1)/2 次,我在这里看不到捷径,但这并不能说明平均案例比较数。你能设置更多关于输入集的约束吗?
标签: php arrays algorithm complexity-theory