【问题标题】:How can i merge items of a Laravel Collection based on keys?如何根据键合并 Laravel 集合的项目?
【发布时间】:2020-03-10 13:54:20
【问题描述】:

我有一个 Laravel 集合,里面有很多类似的重复项:

[
  id: 'NAME1',
  prop1: 'yes',
  prop2: null,
  prop3: 'bla',
  prop4: null
],
[
  id: 'NAME1',
  prop1: null,
  prop2: 'yes'
  prop3: null,
  prop4: 'bla'
]

我想合并具有相同“id”属性的元素,并得到一个这样的集合,同时保留两个属性:

[
  id: 'NAME1',
  prop1: 'yes',
  prop2: 'yes',
  prop3: 'bla',
  prop4: 'bla'
]

当我使用$collection->unique('id') 时,我只得到一个这样的集合,丢失了 prop2 和 prop4 第二个元素:

[
  id: 'NAME1',
  prop1: 'yes',
  prop2: null,
  prop3: 'bla',
  prop4: null
]

我该如何解决?当元素之一具有空键时,我没有找到任何可以合并 Collection 元素的 Laravel Collections 方法。

【问题讨论】:

  • 我认为集合上没有解决此问题的功能。您可能需要编写自己的函数。您可以 array_walk 对集合进行比较并比较数组。
  • 那么,如果不迭代所有元素就没有办法做到这一点?
  • 我当然无法想象任何其他方式来做到这一点。您需要遍历第一个集合并从中构建一个结果集合,检查字段以填充非 NULL 值。而且,如果遇到多个非唯一值,您还必须决定该怎么做......例如,在 OP 中,如果(比如)第一条记录的 prop1 是(比如)"no."所以,你自己设计的算法,适合你的目的。

标签: php laravel collections


【解决方案1】:

这是一个可以做你想做的事情的宏:

use Illuminate\Support\Collection;

Collection::macro('mergeByKey', function ($key) {
    return $this->groupBy($key)->map(function($group) {

        $filteredGroup = collect($group)->map(function($item) {
            return collect($item)->reject(function($value, $key) {
                return $value === null; 
            });
        });

        return array_merge(...$filteredGroup->toArray());
    })->values();
});

然后你可以在这样的集合上使用它:

$collection = collect([
    [
        'id' => 'NAME1',
        'prop1' => 'yes',
        'prop2' => null,
        'prop3' => 'bla',
        'prop4' => null
    ],
    [
        'id' => 'NAME1',
        'prop1' => null,
        'prop2' => 'yes',
        'prop3' => null,
        'prop4' => 'bla'
    ],
    [
        'id' => 'NAME2',
        'prop1' => null,
        'prop2' => 'fdsa',
        'prop3' => null,
        'prop4' => 'asdf'
    ],
    [
        'id' => 'NAME2',
        'prop1' => 'fdsa',
        'prop2' => null,
        'prop3' => 'asdf',
        'prop4' => null
    ],
]);


$result = $collection->mergeByKey('id');

结果:

Collection {#268 ▼
  #items: array:2 [▼
    0 => array:5 [▼
      "id" => "NAME1"
      "prop1" => "yes"
      "prop3" => "bla"
      "prop2" => "yes"
      "prop4" => "bla"
    ]
    1 => array:5 [▼
      "id" => "NAME2"
      "prop2" => "fdsa"
      "prop4" => "asdf"
      "prop1" => "fdsa"
      "prop3" => "asdf"
    ]
  ]
}

【讨论】:

    【解决方案2】:

    所以你想合并每个 id 的所有非空属性(你的列表中只有一个 ID,但我假设可能有很多) 1) 按 id 分组并获取 [id => [id 的所有属性列表]] 的列表 2)对于每个ID: 2a) 从每个列表中删除空属性 2b) 将所有列表合并为一个

    使用 laravel 集合可以这样实现:

    $data = '[
    {
    "id": "NAME1",
    "prop1": "yes",
    "prop2": null,
    "prop3": "bla",
    "prop4": null
    },
    {
    "id": "NAME1",
    "prop1": null,
    "prop2": "yes",
    "prop3": null,
    "prop4": "bla"
    },
    {
    "id": "NAME2",
    "prop1": "no",
    "prop2": "dah",
    "prop4": "bla"
    }
    
    ]
    ';
    
          $coll = collect(json_decode($data, JSON_OBJECT_AS_ARRAY))
            ->groupBy('id')
            ->map(function ($propGroup) {
              //for each group of 'objects' of property lists
              return $propGroup
                ->map(function ($props) {
                  //remove empty properties
                  return collect($props)->filter(function ($prop) {
                    return !empty($prop);
                  });
                })
                ->reduce(function ($carry, $item) {
                  return $carry->merge($item);
                }, collect());
            });
    

    【讨论】:

      猜你喜欢
      • 2022-09-23
      • 2018-11-11
      • 2016-05-07
      • 2016-10-01
      • 2017-05-01
      • 2016-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多