比较没有顺序或键匹配的多维数组

问题描述 投票:0回答:2

我正在使用第三方RESTful API数据更新MySQL数据库表。此更新每天触发几次,因此为了简化过程,我决定在插入新的“新”API数据之前简单地截断数据库表。但是,这导致了两个主要问题:

a)进程执行时表变为空(这是一个实时站点),

b)在执行插入操作时,MySQL服务器有时无法截断表。这导致记录重复,有时甚至翻两番。

我可以将截断和插入放入一个MySQL事务中,但这仍然无法解决问题(a)。

我决定以不同的方式解决问题:

首先,我将API数据和本地数据收集到两个结构相同的数组中,按键(ASC)和值(ASC)排序。这是一个例子:

$local = [
    ['categoryId' => '547d8fd5','programId' => '0714f2cb'],
    ['categoryId' => '547d8fd5','programId' => '0914f2cb'],
]

$remote = [
    ['categoryId' => '547d8fd5','programId' => '0714f2cb'],
    ['categoryId' => '547d8fd5','programId' => '0814f2cb'],
]

然后我将使用以下方法比较两个数组:

public static function arrayDiffAssocRecursive($array1, $array2)
    {
        foreach($array1 as $key => $value) {
            if (is_array($value)) {
                if (!isset($array2[$key])) {
                    $difference[] = $value;
                } elseif(!is_array($array2[$key])) {
                    $difference[] = $value;
                } else {
                    $new_diff = self::arrayDiffAssocRecursive($value, $array2[$key]);
                    if ($new_diff != FALSE) {
                        $difference[] = $array1[$key];
                    }
                }
            } elseif (!isset($array2[$key]) || $array2[$key] != $value) {
                $difference[] = $value;
            }
        }
        return !isset($difference) ? null : $difference;
    }

要获取需要添加的记录,我将按以下顺序使用参数调用上述方法:

$add = Comparator::arrayDiffAssocRecursive($remote, $local);

为了获取需要删除的记录,我将翻转参数:

$delete = Comparator::arrayDiffAssocRecursive($local, $remote);

只要两个数组均等地排序并具有相同数量的记录,该方法就可以工作,但是如果一个或另一个缺少一个或多个记录,则所有剩余记录将不匹配,因此标记为删除和添加,无论它们是否相同保持不变。这种方法有效,但我仍觉得它效率低下。

我想要看到的是一种方法,它可以比较两个数组并返回不匹配的记录,而不管数组的顺序或记录总数。这是可行的还是我完全以错误的方式接近这个?

php mysql arrays multidimensional-array
2个回答
0
投票

使用替换而不是插入。只要您拥有不变的主键,它就会根据主键进行更新。如果主键已存在,则进行更新,否则执行插入操作。


0
投票

我最终使用json_encode()将二级数组元素压缩成字符串。然后我使用array_diff()来收集不匹配的元素,最后我使用json_decode()$add$delete数组返回到它们的原始状态。

现在我不再需要担心按ASC顺序或它们的键匹配两个数组,因为array_diff()将发现不同的元素,无论它们位于何处。

如果你想知道为什么我使用json编码/解码vs序列化/反序列化 - 根据另一个stackoverflow线程,json执行得更快。

class ComparatorTest extends TestCase
{
    private $arrayA;
    private $arrayB;
    private $expectedA;
    private $expectedB;

    public function setUp()
    {
        parent::setUp();

        $this->arrayA = [
            ['key1' => '000','key2' => '8989'],
            ['key1' => '123','key2' => '354'],
            ['key1' => 'aaa','key2' => 'sbbb'],
        ];

        $this->arrayB = [
            ['key1' => '123','key2' => '354'],
            ['key1' => 'aaa','key3' => 'asdf'],
            ['key1' => '654','key2' => '8989'],
        ];

        $this->expectedA = [
            ['key1' => '000','key2' => '8989'],
            ['key1' => 'aaa','key2' => 'sbbb']
        ];

        $this->expectedB = [
            ['key1' => 'aaa','key3' => 'asdf'],
            ['key1' => '654','key2' => '8989'],
        ];
    }

    public function testArrayDiffAssocRecursive()
    {
        $a = $this->flattenSecondLevelArray($this->arrayA);
        $b = $this->flattenSecondLevelArray($this->arrayB);

        $addFlat = array_diff($a, $b);
        $deleteFlat = array_diff($b, $a);

        $add = [];
        if (!empty($addFlat)) {
            foreach($addFlat as $row) {
                $add[] = json_decode($row, true);
            }
        }

        $delete = [];
        if (!empty($deleteFlat)) {
            foreach($deleteFlat as $row) {
                $delete[] = json_decode($row, true);
            }
        }

        $this->assertEquals($this->expectedA, $add);
        $this->assertEquals($this->expectedB, $delete);
    }

    private function flattenSecondLevelArray($array)
    {
        $flat = [];
        if(!empty($array) && is_array($array)) {
            foreach ($array as $pair) {
                $flat[] = json_encode($pair);
            }
        }
        return $flat;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.