【问题标题】:Complex Laravel collection复杂的 Laravel 集合
【发布时间】:2017-08-05 20:47:22
【问题描述】:

我在使用 Laravel Collection 类时遇到了一些问题。

我想做的事:

  • 我有一个多站点解决方案,其中一个站点有“促进者”。有时一位辅导员会出现在多个网站上,而不仅仅是一位。
  • 我想在主页上列出所有促进者和他们所在的网站,但我不希望有多个用户。

所以我现在做的是:

  • 获取引导者。
  • 使用 Collection 收集促进者并使用unique('name')

这给了我独特的促进者,但只选择它检测到的第一个,然后删除其他的。

假设我有这个收藏:

Collection { 
  #items: array:3 [
    0 => array:2 [
      "name" => "John"
      "site" => "Example"
    ]
    1 => array:2 [
      "name" => "Martin"
      "site" => "Another"
    ]
    2 => array:2 [
      "name" => "John"
      "site" => "Another"
    ]
  ]
}

unique() 我会得到:

Collection { 
  #items: array:3 [
    0 => array:2 [
      "name" => "John"
      "site" => "Example"
    ]
    1 => array:2 [
      "name" => "Martin"
      "site" => "Another"
    ]
  ]
}

这就是我想要得到的:

Collection { 
  #items: array:3 [
    0 => array:2 [
      "name" => "John"
      "site" => ["Example", "Another"]
    ]
    1 => array:2 [
      "name" => "Martin"
      "site" => "Another"
    ]
  ]
}

有人知道我如何使用 Laravel 的集合类来实现这一点吗?

【问题讨论】:

  • 你为什么不使用Group_concat ?这可能会解决您的问题。
  • 该站点未在数据库级别分配给用户。我正在遍历所有站点,找到它们的促进者,然后将站点名称添加到促进者对象中。我真的必须用这个集合来做这件事。基本上我要做的是:获取唯一但合并一个键。
  • 尝试使用GroupBy。这是示例。这可能会对您有所帮助。 laravel.com/docs/5.4/collections#method-groupby

标签: php arrays laravel laravel-5 collections


【解决方案1】:

当遇到收藏问题时,请始终记住 reduce 是您武器库中的强大工具。

基于我无法开始工作的 Sam 的回答,我认为与 groupBy 一起使用 reduce 应该可以工作......

$sites = collect([
  ["name" => "John", "site" => "Example"],
  ["name" => "Martin", "site" => "Another"],
  ["name" => "John", "site" => "Another"],
]);

$sites->groupBy('name')->reduce(function ($result, $item) {
  $result[] = [
    'name' => $item->first()['name'], 
    'sites' => $item->pluck('site')->toArray()
  ];

  return $result;
}, collect([]))->toArray();

从控制台...

λ php artisan tinker                                                                             
Psy Shell v0.8.2 (PHP 7.0.10 ÔÇö cli) by Justin Hileman                                          
>>> $sites = collect([                                                                           
...   ["name" => "John", "site" => "Example"],                                                   
...   ["name" => "Martin", "site" => "Another"],                                                 
...   ["name" => "John", "site" => "Another"],                                                   
... ]);                                                                                          
=> Illuminate\Support\Collection {#698                                                           
     all: [                                                                                      
       [                                                                                         
         "name" => "John",                                                                       
         "site" => "Example",                                                                    
       ],                                                                                        
       [                                                                                         
         "name" => "Martin",                                                                     
         "site" => "Another",                                                                    
       ],                                                                                        
       [                                                                                         
         "name" => "John",                                                                       
         "site" => "Another",                                                                    
       ],                                                                                        
     ],                                                                                          
   }                                                                                             
>>> $sites->groupBy('name')->reduce(function ($result, $item) {                                  
...   $result[] = ['name' => $item->first()['name'], 'sites' => $item->pluck('site')->toArray()];
...                                                                                              
...   return $result;                                                                            
... }, collect([]))->toArray();                                                                  
=> [                                                                                             
     [                                                                                           
       "name" => "John",                                                                         
       "sites" => [                                                                              
         "Example",                                                                              
         "Another",                                                                              
       ],                                                                                        
     ],                                                                                          
     [                                                                                           
       "name" => "Martin",                                                                       
       "sites" => [                                                                              
         "Another",                                                                              
       ],                                                                                        
     ],                                                                                          
   ]                                                                                             

需要注意的一点是,您在问题中指定如果只有一个站点,则站点应返回单个字符串,如果有很多站点,则应返回数组。上述解决方案不提供此功能!我认为这是不一致的,您应该始终为站点键返回一个数组,即使它只有一个值,因为它会使以后更难阅读和操作。

但是,如果这很重要,您可以在使用 pluck 设置数组时检查是否有多个站点,如果没有,您可以将其设置为单个字符串,如下所示:

$sites->groupBy('name')->reduce(function ($result, $item) {
  $result[] = [
    'name' => $item->first()['name'],
    'sites' => $item->pluck('site')->count() > 1 ? $item->pluck('site') : $item->first()['site']
  ];

  return $result;
}, collect([]))->toArray();

这会产生...

[                        
  [                      
    "name" => "John",    
    "sites" => [         
      "Example",         
      "Another",         
    ],                   
  ],                     
  [                      
    "name" => "Martin",  
    "sites" => "Another",
  ],                     
]                        

【讨论】:

  • 完美!这正是我想要做的。我将深入研究 reduce 方法,这似乎是一个非常强大的方法。谢谢
  • 太棒了!是的,您实际上可以使用 reduce 重新实现任何收集方法。如果您想更深入地使用集合,我强烈推荐此资源:adamwathan.me/refactoring-to-collections - 快乐编码!
  • @haakym 很好的答案。你的回答真的很可观。坚持下去。上帝保佑你。
  • 谢谢曼尼什!也祝你好运。感谢 Sam 在我开始从他的答案开始工作时发布了第一个答案,因为我最初的解决方案是只使用 reduce ,这变得有点复杂。
【解决方案2】:

假设 $collection 是主集合,你可以通过链接来获得你想要的东西

 $collection->groupBy('name')->map(function($facilitators) {
     return ['name' => $facilitators->first()['name'], 'site' => $facilitators->pluck('site')->toArray()];
})->values()->toArray();

首先我们按名称分组,因此它将在集合中给出二维数组,然后迭代到该名称将是通用的,因此从第一个元素获取它,然后从所有元素提取站点并将其转换为数组,使用 flatMap 将使其单级嵌套。

【讨论】:

  • 你运行过这段代码吗?它对我不起作用。 $facilitators->first()->name 将返回一个无法访问名称的错误,因为我认为 first() 方法返回一个数组,而您正试图像访问对象一样访问它。
  • 除了 toArray() 和 all() 首先返回集合中的第一个项目并且该项目是我认为的对象并且项目本身是数组然后它需要一点修改但显示的转储似乎有嵌套集合
猜你喜欢
  • 2017-01-02
  • 1970-01-01
  • 2019-09-30
  • 1970-01-01
  • 2013-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-17
相关资源
最近更新 更多