【问题标题】:compare two collection arrays in laravel比较laravel中的两个集合数组
【发布时间】:2020-04-06 21:47:02
【问题描述】:

我正在使用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],
];

所以我需要知道它们是否相同,比较两个集合。并且如果在某些数组中,其中一个键(或多个键)具有不同的值,则它们将不再是相同的集合,例如,在 1 个集合中,第二个项目的价格为 800,而另一个集合400. 有任何 laravel 集合的本机方法可以做到这一点吗?或者我如何使用简单的 php 数组来做到这一点?

【问题讨论】:

标签: php arrays laravel


【解决方案1】:

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

$collection1->diff($collection2);

它返回一个 Illuminate\Support\Enumerable 类。 您可以通过调用 all() 来获取项目:

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

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

$differentItems->all();

// [1, 3, 5]

此代码属于 laravel 文档。 https://laravel.com/docs/7.x/collections#method-diff 。 最后,您可以将 $differentItems 转换为布尔值。像这样:

$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_diffhttps://laravel.com/api/7.x/Illuminate/Support/Enumerable.html

【讨论】:

  • 这显然行不通,因为集合中的元素是数组。
  • @AliKhalili 然后将数组转换为集合并检查例如collect($collection1)->diff(collect($collection2))->isEmpty();
  • 请在您的答案中添加一些解释,以便其他人学习
  • 虽然这段代码可能会解决问题,包括解释如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提出问题的人。请编辑您的答案以添加解释并说明适用的限制和假设。你可能想看看How to Answer
【解决方案2】:

遵循比较函数:

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

【讨论】:

    【解决方案3】:

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

        $serialize1 = $collection1->map(function ($item) {
            return serialize($item);
        });
    
        $serialize2 = $collection2->map(function ($item) {
            return serialize($item);
        });
    
    dd($serialize1->diff($serialize2)->isEmpty());
    

    【讨论】:

    • 序列化不是比较数组的正确方法。更改键/值数组中项目的顺序会更改序列化结果,从逻辑上讲,它不会影响数组相等性。
    【解决方案4】:

    据我所知,由于您的集合项目是数组,因此没有原生的简单 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));
    

    【讨论】:

      【解决方案5】:

      此方法仅在两个集合具有相同键顺序时才有效。

      默认情况下,Laravel 有一个 diffAssoc 方法,它实际上比较集合的单个项目。如果要比较两个集合数组,则必须创建自己的解决方案。

      这是我创建(或者您可以说扩展)收集方法的解决方案。

      首先我映射每个项目并序列化项目,然后对另一个集合执行相同操作。使用 diffAssoc 方法获取差异,并反序列化最终输出。

      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);
      

      请注意,这个新方法返回另一个集合(基于非零)。这没有 diffAssoc 的 'all()' 方法。 如果您想要一个从零开始的索引数组,请使用 values 函数。

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

      【讨论】:

        猜你喜欢
        • 2021-12-20
        • 2021-03-12
        • 1970-01-01
        • 2019-02-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-09
        相关资源
        最近更新 更多