php 在laravel中比较两个集合数组

ocebsuys  于 4个月前  发布在  PHP
关注(0)|答案(6)|浏览(55)

我正在使用laravel,我有两个集合数组,看起来像这样:

$collection1 = [
    ['id' => 1, 'name'=> 'phone', 'quantity' => 1, 'price' => 1200],
    ['id' => 2, 'name'=> 'tv', 'quantity' => 3, 'price' => 800],
];

$collection2 = [
    ['id' => 1, 'name'=> 'phone', 'quantity' => 1, 'price' => 1200],
    ['id' => 2, 'name'=> 'tv', 'quantity' => 3, 'price' => 400],
];

字符串
所以我需要知道它们是否相同,比较两个集合。如果在一些数组中,其中一个键(或几个)具有不同的值,那么它们将不再是相同的集合,例如在一个集合中,第二个项目的价格具有800的值,而另一个集合的价格为400。如何用PHP数组实现这一点?

5f0d552i

5f0d552i1#

laravel集合有一个叫做diff的方法,使用这个方法你可以获取集合中不存在于给定项目中的项目。项目是$collection2,它可以是一个数组或一个集合,所以你可以像这样在这两个集合之间获取不同的项目。

$collection1->diff($collection2);

字符串
它返回一个Illuminate\Support\Escort类。你可以通过调用all()来获取这些项:

$collection = collect([1, 2, 3, 4, 5]);

$differentItems = $collection->diff([2, 4, 6, 8]);

$differentItems->all();

// [1, 3, 5]


这段代码属于laravel docs. https://laravel.com/docs/7.x/collections#method-diff.在最后你可以把$differentItems转换为boolean.像这样:

$collection = collect([1, 2, 3, 4, 5]);
$differentItems = $collection->diff([2, 4, 6, 8]);
$differentItems->isEmpty();
// return false

$collection = collect([1, 2, 3, 4, 5]);
$differentItems = $collection->diff($collection);
$differentItems->isEmpty();
// return true


更多链接https://laravel.com/api/7.x/Illuminate/Support/Collection.html#method_diff https://laravel.com/api/7.x/Illuminate/Support/Enumerable.html

2hh7jdfx

2hh7jdfx2#

所以首先序列化每个元素,然后进行比较。

$serialize1 = $collection1->map(function ($item) {
        return serialize($item);
    });

    $serialize2 = $collection2->map(function ($item) {
        return serialize($item);
    });

dd($serialize1->diff($serialize2)->isEmpty());

字符串

7hiiyaii

7hiiyaii3#

遵循比较函数:

function compareCollections($c1, $c2) {
    // If the colletions have different sizes we return false:
    if (count($c1) != count($c2)) {
        return false;
    }

    // The collections have the same size, we check element by element:
    foreach($c1 as $item) {

        // We find the current element in $c1 in $c2:
        $itemToCompare = array_filter($c2, function ($compareItem) use ($item) {
            return ($compareItem['id'] == $item['id']);
        });

        // If we did not find the element in $c2, the collections are different:
        if (empty($itemToCompare)) {
            return false;
        }

        $itemToCompare = current($itemToCompare);

        // We now use PHP to check the element keys:
        $diff = array_diff_key($item, $itemToCompare);

        // If there is a different, return false:
        if (!empty($diff)) {
            return false;
        }       
    }

    // If everything is ok until here, the collections are the same:
    return true;
}

字符串
还有一个测试:

$collection1 = [
    ['id' => 1, 'name'=> 'phone', 'quantity' => 1, 'price' => 1200],
    ['id' => 2, 'name'=> 'tv', 'quantity' => 3, 'price' => 800],
];

$collection2 = [
    ['id' => 1, 'name'=> 'phone', 'quantity' => 1, 'price' => 1200],
    ['id' => 2, 'name'=> 'tv', 'quantity' => 3, 'price' => 400],
];

$collection3 = [
    ['id' => 1, 'name'=> 'tv', 'quantity' => 1, 'price' => 1200],
    ['id' => 2, 'name'=> 'tv', 'quantity' => 3],
];

var_dump(compareCollections($collection1, $collection2)); // true
var_dump(compareCollections($collection1, $collection3)); // false

0vvn1miw

0vvn1miw4#

据我所知,因为你的集合项是数组,所以没有简单的Laravel原生方法来做到这一点,你应该写一个函数来比较它们:
所以,假设,你有:

$collection1 = collectt([
    ['id' => 1, 'name'=> 'phone', 'quantity' => 1, 'price' => 1200],
    ['id' => 2, 'name'=> 'tv', 'quantity' => 3, 'price' => 800],
]);

$collection2 = collect([
    ['id' => 1, 'name'=> 'phone', 'quantity' => 1, 'price' => 1200],
    ['id' => 2, 'name'=> 'tv', 'quantity' => 3, 'price' => 400],
]);

字符串
例如,您可以通过以下方式比较它们:

private function collectionsAreEqual($collection1, $collection2)
    {
        if ($collection1->count() != $collection2->count()) {
            return false;
        }
        //assuming that, from each id, you don't have more that one item:
        $collection2 = $collection2->keyBy('id');
        foreach ($collection1->keyBy('id') as $id => $item) {
            if (!isset($collection2[$id])) {
                return false;
            }
            //your items in the collection are key value arrays 
            // and can compare them with == operator
            if ($collection2[$id] != $item) {
                return false;
            }
        }
        return true;
    }
    dd(collectionsAreEqual($collection1, $collection2));

eiee3dmh

eiee3dmh5#

此方法仅在两个集合具有相同的键顺序时有效。
默认情况下,Laravel有一个diffAsk方法,它实际上是比较集合中的单个元素。如果你想比较两个集合数组,那么你必须创建自己的解决方案。
下面是我的解决方案,我创建(或者你可以说扩展)一个集合方法。
首先我Map每个元素并序列化,然后对另一个集合做同样的操作。通过使用diffAsynchronous方法获得差异并反序列化最终输出。

  • AppServiceProvider.php*
<?php

namespace App\Providers;

use Illuminate\Support\Collection;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Collection::macro('diffAssocMultiple', function ($anotherCollection) {
            /* @var $this Collection */
            return $this->map(function($arr) {
                return serialize($arr);
            })->diffAssoc($anotherCollection->map(function($arr) {
                return serialize($arr);
            }))->map(function($arr) {
                return unserialize($arr);
            });
        });
    }
}

字符串
使用

$diff = $collectionOne->diffAssocMultiple($collectionTwo);


请注意,这个新方法返回另一个集合(非零基)。并且它没有diffAsk所具有的“all()”方法。如果你想要一个零基索引数组,那么使用values函数沿着。

$diff = $collectionOne->diffAssocMultiple($collectionTwo)->values();

lc8prwob

lc8prwob6#

我最后只是比较了toJson()的集合的输出,我不能说这在性能上有多差,但对我的情况(单元测试)来说还不错。

相关问题