【问题标题】:Unique array values with callback具有回调的唯一数组值
【发布时间】:2013-09-16 10:39:07
【问题描述】:

所以,

问题

第一种情况

我有一个包含一些值的数组 - 首先,让它们都是字符串(或者可以简单地视为字符串)。示例:

$rgData = ['foo', 'feo', 'bar', 'baz', 'bee'];

现在,我想从中创建唯一数组,其中两个项目之间的Levenshtein distance 小于 2。即如果levenshtein($x, $y) < 2,项目$x$y 被视为相等。例如,foofeo 相等,barbaz - 但不是 barbee

第二种情况

我有一个数组,每个点的坐标为[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 =&gt; xFz - 例如,levenshtein() 是不及物。因此,在常见情况中,整个结果将至少取决于项目顺序(但不仅仅是来自它)——现在这对我来说不是问题,因为我确定我的数据顺序和内容(或者,至少,barbaz 是否将通过 levenshtein 比较返回无关紧要)。所以,我的目标是尽量减少比较次数(我认为,比较函数传递或不改变什么都不会改变,因为我想优化甚至重新创建比较算法本身)

【问题讨论】:

  • 性能不是您的第一个问题,因为您的比较功能不是transitive,结果取决于您不想要的输入顺序,我认为,请参阅3v4l.org/vQZVg
  • 当然不是(并且在常见情况下它不能通过问题的定义传递)。我知道,如果我以这种方式定义我的比较函数,那么结果将至少取决于项目顺序。所以现在这对我来说不是问题
  • @AlmaDoMundo 结果取决于输入顺序,比较方法事先未知,我怀疑您的功能可以“优化”到什么程度:您无法重新排列项目,也无法“猜测”/“预测” " 基于历史的两个项目的距离。
  • @Passerby 但我的问题是关于方法本身 - 即如何最小化比较操作的数量?好的,想象一下比较函数将是传递的——这不会改变我的目标(即获得一个比较次数最少的结果)
  • 你说:有一个集合,你想计算它有多少组,其中组表示给定函数 G(a,b)=>T/F 告诉 a,b 在同一个组中.如果对您的输入集没有任何进一步的了解,您需要在最坏的情况下比较 n(n-1)/2 次,我在这里看不到捷径,但这并不能说明平均案例比较数。你能设置更多关于输入集的约束吗?

标签: php arrays algorithm complexity-theory


【解决方案1】:

输入集 = {a,b,c,...} 矩阵,

   a b c . . .
a  1
b  1 1
C  0 0 1
.        1
.          1
.            1

1 如果两个元素在同一组中,1s 在对角线 couse 反射属性,计算 olny 下三角形 couse symetric 属性。在第 n 行,如果找到匹配项,则开始与 cols 进行比较,放入 1,然后删除第 n 个 col,形成进一步的比较。我希望它是可以理解的。

最坏的情况:如果每个组都有一个元素。

【讨论】:

  • 这里ABC .. 是原始集合X 的精确子集吗? IE。 A U B U C U .. = XA П B П C П .. = 0? (这里П 是交集,0 是空集)
  • 如果它们是元素 - 那么你的假设是:创建 A、B、C、..(正如我在上面的评论中描述的那样)需要 N(N-1)/2 个比较。对吗?
  • 或更少,下三角形中的元素
  • 好的,明白了。它似乎并不严格,但描述了最坏的情况已经足够好了。谢谢。
  • 你可以尝试一个devide和merge实现,它可能在平均情况下有很大的好处,而在最坏的情况下稍微高一点
猜你喜欢
  • 1970-01-01
  • 2019-02-12
  • 1970-01-01
  • 2016-06-07
  • 2021-12-27
  • 2012-08-27
  • 1970-01-01
  • 2011-03-11
  • 1970-01-01
相关资源
最近更新 更多