我如何找到模糊的重复从这个php数组


How do I find fuzzy duplicates from this php array?

在我添加澄清之前,这里有一些伪数据。我需要迭代的数组是这样的:

$ipBodies = array(
    '1.2.3.4' => array(
        array('id' => 1, 'body' => 'asdfasdfasdf_X'),
        array('id' => 2, 'body' => 'asdfasdfasdf_Y'),
        array('id' => 3, 'body' => '123456789_X'),
        array('id' => 4, 'body' => '123456789_Y'),
    ),
    '5.6.7.8' => array(
        array('id' => 13, 'body' => 'foobarbaz_X'),
        array('id' => 14, 'body' => 'foobarbaz_Y'),
        array('id' => 15, 'body' => 'adsflkjlsdfjlkjlkasdfj'),
        array('id' => 16, 'body' => 'foobarbaz_Z'),
    ),
);

因此,从这个示例数据中,您可以看到在1.2.3.4数组中有两组唯一的"模糊重复",而在5.6.7.8数组中只有1组"模糊重复"。

在真实数据中,一切都按比例放大。主数组将有数百个ip地址,这些数组可能有数百个成员。body部分在实际数据中更大。

我认为我需要运行每个ip地址数组,并创建每个组合的新数组到一个新数组,例如$pairs,然后运行similar_text(似乎对此工作得很好),以找到重复项,但创建这些对集将是昂贵的我相信。我认为$pairs数组计数最终将是数组计数的阶乘,随着数组大小的增加,它可能变得非常大。

我想我想结束与数组$dupes(基于上面的样本数据)应该看起来像这样:

$dupes = array(
    '1.2.3.4' => array(
        array('1', '2'),
        array('3', '4'),
    ),
    '5.6.7.8' => array(
        array('13', '14', '16'),
    ),
);
我真的需要一些帮助和建议,这样我就可以开始解决这个问题了。天啊,我希望我的解释有道理。如果没有,请告诉我,我将澄清。

如果可能的话,我建议使用levenshtein而不是similar_text,因为它是一个更快的算法。

算法复杂度为O(m*n),其中n、m为str1和str2的长度(与similar_text()相比相当好),这是O(max(n,m)**3),但仍然很昂贵)。

下面的代码使用关联数组将每个元素放入到ip['body']的距离为<2(这意味着同一桶内的匹配最多有1个不同的字符,根据需要进行更改)。一旦所有元素都被放入各自的桶中,每个只有1个元素的桶将被丢弃。

$ipBodies = array(
    '1.2.3.4' => array(
        array('id' => 1, 'body' => 'asdfasdfasdf_X'),
        array('id' => 2, 'body' => 'asdfasdfasdf_Y'),
        array('id' => 3, 'body' => '123456789_X'),
        array('id' => 4, 'body' => '123456789_Y'),
    ),
    '5.6.7.8' => array(
        array('id' => 13, 'body' => 'foobarbaz_X'),
        array('id' => 14, 'body' => 'foobarbaz_Y'),
        array('id' => 15, 'body' => 'adsflkjlsdfjlkjlkasdfj'),
        array('id' => 16, 'body' => 'foobarbaz_Z'),
    ),
);
$counts = [];
foreach($ipBodies as $groupName => $group) {
    $counts[$groupName] = [];
    foreach($group as $key => $ip) {
        foreach($counts[$groupName] as $countGroup => $groupCount) {
            if(levenshtein($ip['body'],$countGroup) < 2) {
                $counts[$groupName][$countGroup][] = $ip['id'];
                continue 2;
            }
        }
        $counts[$groupName][$ip['body']] = [$ip['id']];
    }        
}
//remove elements that appear just once
foreach($counts as $groupName => &$groupCounts) {
    foreach($groupCounts as $k => &$v) {
        if(count($v) < 2) {
            unset($counts[$groupName][$k]);
        }
    }
    $counts[$groupName] = array_values($groupCounts);
}
print_r($counts);

Array
(
    [1.2.3.4] => Array
        (
            [0] => Array
                (
                    [0] => 1
                    [1] => 2
                )
            [1] => Array
                (
                    [0] => 3
                    [1] => 4
                )
        )
    [5.6.7.8] => Array
        (
            [0] => Array
                (
                    [0] => 13
                    [1] => 14
                    [2] => 16
                )
        )
)