Laravel 集合 - 列出多个值

Laravel collections - list multiple values

我想获取一个集合和 return 包含集合中两个字段的平面数组。我想要的:

$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 编写一个包装器..

您可以使用

$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"
 ]
]

如果您想专门使用集合,您可以扩展当前集合 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);
});

在上面的示例中,我将密钥作为 return 的一部分包含在内,但可以将其删除。

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

会给你想要的东西。

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

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

我修改了 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);
    });  

如果您使用 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