【问题标题】:Laravel collections - list multiple valuesLaravel 集合 - 列出多个值
【发布时间】:2016-03-11 19:51:23
【问题描述】:

我正在寻找一个集合并返回包含集合中两个字段的平面数组。我想要什么:

$collection = new Collection([
    [
        "a"=>"a1",
        "b"=>"b1",
        "c"=>"c1"
    ],
    [
        "a"=>"a2",
        "b"=>"b2",
        "c"=>"c2"
    ],
    [
        "a"=>"a3",
        "b"=>"b3",
        "c"=>"c3"
    ]
]);

//desired output:
[
    ["a1","b1"],
    ["a2","b2"],
    ["a3","b3"]
];

我以为这是一个函数,但事实并非如此:

$collection->lists(["a","b"]);

考虑到这些可能有数千行,我当前的解决方案似乎效率不高:

$collection->lists("a")->zip($collection->lists("b"));

有没有我缺少的功能?谢谢。

编辑:我也使用过这样的地图:

$collection->map(function($row)){
    return [$row['a'],$row['b']];
}

这似乎比我想要的更习惯。如果没有原生方式,我可能最终会用这个函数为 Collection 编写一个包装器..

【问题讨论】:

    标签: laravel collections laravel-5.2


    【解决方案1】:

    如果您想专门使用集合,您可以扩展当前的集合 API,因为它是可宏的,执行以下操作:

    Collection::macro('pluckMultiple', function ($assoc) {
        return $this->map(function ($item) use ($assoc) {
            $list = [];
            foreach ($assoc as $key) {
                $list[$key] = data_get($item, $key);
            }
            return $list;
        }, new static);
    });
    

    在上面的示例中,我将键作为返回的一部分,但可以删除。

    $collection->pluckMultiple(['a', 'b']);
    

    会给你你想要的。

    如果您想从 Eloquent 集合中提取项目,上述方法可以很好地工作,例如:

    $books = Book::with('author')->get();
    $books->pluckMultiple(['title', 'author.name', 'author.surname']);
    

    【讨论】:

    • 这是一个很好的解决方案,谢谢。我实际上对此感到震惊,并惊讶地发现 pluck 方法默认不接受这个。对我来说似乎应该这样做。
    • 这应该写在哪个文件里?
    • @Ken 您可以通过多种方式做到这一点。如果你没有很多宏,你可以把它放在你的AppServiceProviderregister 方法中。或者,您可以检查以下forum thread 的替代方案,将它们分组到一个文件中并使用自动加载。
    【解决方案2】:

    你可以使用

    $plucked = $collection->pluck('b','a');
    
    $plucked->all();
    

    这将给出以下结果

    Collection {#651 ▼
    #items: array:3 [▼
    "a1" => "b1"
    "a2" => "b2"
    "a3" => "b3"
    ]}
    

    并使用此代码获取给定的格式

    foreach ($plucked as $key => $item)
    {
     $temp[] = [ $key, $item];
    }
    

    这将给出以下结果。

    array:3 [▼
     0 => array:2 [▼
      0 => "a1"
      1 => "b1"
      ]
     1 => array:2 [▼
      0 => "a2"
      1 => "b2"
      ]
     2 => array:2 [▼
      0 => "a3"
      1 => "b3"
     ]
    ]
    

    【讨论】:

    • 我想避免多次遍历数组。我知道我可以使用map() 进行一次迭代,但似乎应该有更好的方法
    • 我不认为有任何直接的函数会给出想要的结果。
    • 谢谢。如果没有其他结果,将接受您的回答
    • 谢谢。如果您找到更好的方法,请告诉我。
    【解决方案3】:

    如果你使用 Laravel 5.0,你会发现 Illuminate\Laravel\Collection 不接受宏,所以 Leon 的优雅解决方案不起作用。如果(像我一样)你不能升级到更新的 Laravel 版本,你可以使用这个函数作为解决方法:

    <?php
    
    use Illuminate\Support\Collection;
    
    /**
     * List values from collection. Unlike $collection->lists('key'), this function allows using multiple keys.
     *
     * In newer Laravel versions things like that can be done with collection macros, but not in 5.0.
     *
     * @param Collection $collection
     * @param array|string $properties
     * @param string $id
     * @return array
     */
    function lists(Collection $collection, $properties, $id = null) {
        $result = [];
        $i = 0;
    
        foreach ($collection as $item) {
            $k = $id ? $item->$id : $i;
            if (is_array($properties)) {
                $result[$k] = [];
                foreach ($properties as $property) {
                    $result[$k][$property] = $item->$property;
                }
            }
            else {
                $result[$k] = $item->$properties;
            }
            $i++;
        }
    
        return $result;
    }
    

    然后你会像这样使用它:

    $users = User::all();
    $someData = lists($collection, ['name', 'email']);
    // Or, if you want to key by id:
    $someData = lists($collection, ['name', 'email'], 'id');
    

    至于你把这个函数放在哪里——我把类似的东西放在 app/Support/helpers.php 中,然后像这样更新我的 composer.json:

    "autoload": {
        ...
        "files": [
            "app/Support/helpers.php"
        ]
    },
    

    然后运行composer dump

    【讨论】:

      【解决方案4】:

      我修改了 Leon Vismer 的答案以在数组中使用点符号。

              Collection::macro('pluckMultiple', function ($assoc) {
              /* @var $this Collection */
              return $this->map(function ($item) use ($assoc) {
                  $list = [];
                  foreach ($assoc as $keys) {
                      $old_key = $keys;
                      $keys    = explode('.', $keys);
                      $ref     = &$list;
      
                      while (count($keys) > 1) {
                          $key = array_shift($keys);
                          if (!isset($ref[ $key ]) || !is_array($ref[ $key ])) {
                              $ref[ $key ] = [];
                          }
      
                          $ref = &$list[ $key ];
                      }
      
                      $ref[ array_shift($keys) ] = data_get($item, $old_key);
                  }
      
                  return $list;
              }, new static);
          });  
      

      【讨论】:

      • 不,输出带有点。而我的代码将点转换为数组。例如:{ customer.name => 'Raza' customer.dob => '1985-01-01' } to { customer { name => 'Raza' dob => '1985-01-01' }
      猜你喜欢
      • 2019-03-30
      • 1970-01-01
      • 2019-06-28
      • 2019-02-09
      • 2017-11-02
      • 1970-01-01
      • 2022-07-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多