集合
[TOC]
简介
Illuminate\Support\Collection 类提供了一个更具可读性和更便于处理数组数据的封装。具体请查看下方示例代码。我们使用 collect辅助函数从数组中创建一个新的集合实例,对其中每一个元素执行strtoupper 函数之后再删除所有的空元素:
$collection = collect(['taylor', 'abigail', null])->map(function ($name) {
return strtoupper($name);
})
->reject(function ($name) {
return empty($name);
});
正如你所见, Collection 类允许你链式调用其它方法,以达到在底层数组上流畅的执行 map 和 reduce 操作,通常,集合是不可变的,这意味着每一个Collection 方法都会返回一个新的 Collection 实例。
创建集合
如上所述,collect 辅助函数会为指定的数组返回一个新的Illuminate\Support\Collection实例。因此,我们可以非常容易的创建一个结合:
$collection = collect([1, 2, 3]);{tip} Eloquent 查询结果总是返回 Collection 实例。
扩展集合
集合都是「可宏扩展」(macroable) 的,它允许你在执行时将其它方法添加到 Collection 类。例如,通过下面的代码在Collection类中添加一个toUpper方法:
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
Collection::macro('toUpper', function () {
return $this->map(function ($value) {
return Str::upper($value);
});
});
$collection = collect(['first', 'second']);
$upper = $collection->toUpper();
// ['FIRST', 'SECOND']
通常,你应该在服务提供者 内声明集合宏。
可用方法
接下来,我们将讨论每个 Collection 类可用的方法。记住,所有这些方法都可以链式调用以流畅地操作底层数组。此外,几乎所有方法都返回一个新的 Collection 实例,允许你在需要时保存集合的原始副本:
all
average
avg
chunk
collapse
collect
combine
concat
contains
containsStrict
count
countBy
crossJoin
dd
diff
diffAssoc
diffKeys
dump
duplicates
duplicatesStrict
each
eachSpread
every
except
filter
first
firstWhere
flatMap
flatten
flip
forget
forPage
get
groupBy
has
implode
intersect
intersectByKeys
isEmpty
isNotEmpty
join
keyBy
keys
last
macro
make
map
mapInto
mapSpread
mapToGroups
mapWithKeys
max
median
merge
mergeRecursive
min
mode
nth
only
pad
partition
pipe
pluck
pop
prepend
pull
push
put
random
reduce
reject
replace
replaceRecursive
reverse
search
shift
shuffle
skip
slice
some
sort
sortBy
sortByDesc
sortDesc
sortKeys
sortKeysDesc
splice
split
sum
take
tap
times
toArray
toJson
transform
union
unique
uniqueStrict
unless
unlessEmpty
unlessNotEmpty
unwrap
values
when
whenEmpty
whenNotEmpty
where
whereStrict
whereBetween
whereIn
whereInStrict
whereInstanceOf
whereNotBetween
whereNotIn
whereNotInStrict
whereNotNull
whereNull
wrap
zip
方法列表
all()
all 方法返回代表集合的底层数组:
collect([1, 2, 3])->all();
// [1, 2, 3]
average() {#collection-method}
avg 方法的别名。
avg() {#collection-method}
avg 方法返回指定键的 平均值 :
$average = collect([['foo' => 10], ['foo' => 10], ['foo' => 20], ['foo' => 40]])->avg('foo');
// 20
$average = collect([1, 1, 2, 4])->avg();
// 2
chunk() {#collection-method}
chunk 方法把集合分割成多个指定大小的较小集合:
$collection = collect([1, 2, 3, 4, 5, 6, 7]);
$chunks = $collection->chunk(4);
$chunks->toArray();
// [[1, 2, 3, 4], [5, 6, 7]]
当使用如 Bootstrap 那样的栅格系统时,该方法在 视图 中相当有用。想象一下你有个想在栅格显示的 Eloquent 模型:
@foreach ($products->chunk(3) as $chunk)
@foreach ($chunk as $product)
@endforeach
@endforeach
collapse() {#collection-method}
collapse 方法把一个多数组集合坍缩为单个扁平的集合:
$collection = collect([[1, 2, 3], [4, 5, 6], [7, 8, 9]]);
$collapsed = $collection->collapse();
$collapsed->all();
// [1, 2, 3, 4, 5, 6, 7, 8, 9]
combine() {#collection-method}
combine 方法将一个集合的值作为键,与另一个数组或集合的值进行结合:
$collection = collect(['name', 'age']);
$combined = $collection->combine(['George', 29]);
$combined->all();
// ['name' => 'George', 'age' => 29]
collect() {#collection-method}
collect 方法返回一个包含当前集合所含元素的新 Collection 实例:
$collectionA = collect([1, 2, 3]);
$collectionB = $collectionA->collect();
$collectionB->all();
// [1, 2, 3]
collect 方法从根本上对将懒集合转换为标准 Collection 实例有用:
$lazyCollection = LazyCollection::make(function () {
yield 1;
yield 2;
yield 3;
});
$collection = $lazyCollection->collect();
get_class($collection);
// 'Illuminate\Support\Collection'
$collection->all();
// [1, 2, 3]{提示} 当你有个 Enumerable 实例并需要一个非懒集合实例时, collect 方法相当有用。由于 collect() 是 Enumerable 契约的一部分,你可以安全地使用它以获取一个 Collection 实例。
concat() {#collection-method}
concat 方法在集合的末端附加指定的 数组 或集合值:
$collection = collect(['John Doe']);
$concatenated = $collection->concat(['Jane Doe'])->concat(['name' => 'Johnny Doe']);
$concatenated->all();
// ['John Doe', 'Jane Doe', 'Johnny Doe']
contains() {#collection-method}
contains 方法检查集合有否包含指定的元素:
$collection = collect(['name' => 'Desk', 'price' => 100]);
$collection->contains('Desk');
// true
$collection->contains('New York');
// false
你也可以传递一个键/值对给 contains 方法,它将检查集合有否存在指定的键/值对:
$collection = collect([
['product' => 'Desk', 'price' => 200],
['product' => 'Chair', 'price' => 100],
]);
$collection->contains('product', 'Bookcase');
// false
最后,你也可以传递一个回调函数给 contains 方法去执行你的真值检验:
$collection = collect([1, 2, 3, 4, 5]);
$collection->contains(function ($value, $key) {
return $value > 5;
});
// false
contains 方法用“松散”比较检查元素值,意味着整数值的字符串会被视同等值的整数。用 containsStrict 方法使用“严格”比较过滤。
containsStrict() {#collection-method}
这个方法和 contains 方法类似;但是它却是使用了「严格」比较来比较所有的值。
{tip} 这个方法的行为当使用 Eloquent Collections会被重写。
count() {#collection-method}
count 方法返回这个集合内集合项的总数量:
$collection = collect([1, 2, 3, 4]);
$collection->count();
// 4
countBy() {#collection-method}
countBy 方法计算集合中每个值的出现次数。默认情况下,该方法计算每个元素的出现次数:
$collection = collect([1, 2, 2, 2, 3]);
$counted = $collection->countBy();
$counted->all();
// [1 => 1, 2 => 3, 3 => 1]
但是,你也可以向 countBy传递一个回调函数来计算自定义的值出现的次数:
$collection = collect(['alice@gmail.com', 'bob@yahoo.com', 'carlos@gmail.com']);
$counted = $collection->countBy(function ($email) {
return substr(strrchr($email, "@"), 1);
});
$counted->all();
// ['gmail.com' => 2, 'yahoo.com' => 1]
crossJoin() {#collection-method}
crossJoin 方法交叉连接指定数组或集合的值,返回所有可能排列的笛卡尔积:
$collection = collect([1, 2]);
$matrix = $collection->crossJoin(['a', 'b']);
$matrix->all();
/*
[
[1, 'a'],
[1, 'b'],
[2, 'a'],
[2, 'b'],
]
*/
$collection = collect([1, 2]);
$matrix = $collection->crossJoin(['a', 'b'], ['I', 'II']);
$matrix->all();
/*
[
[1, 'a', 'I'],
[1, 'a', 'II'],
[1, 'b', 'I'],
[1, 'b', 'II'],
[2, 'a', 'I'],
[2, 'a', 'II'],
[2, 'b', 'I'],
[2, 'b', 'II'],
]
*/
dd() {#collection-method}
dd 方法用于打印集合元素并中断脚本执行:
$collection = collect(['John Doe', 'Jane Doe']);
$collection->dd();
/*
Collection {
#items: array:2 [
0 => "John Doe"
1 => "Jane Doe"
]
}
*/
如果你不想中断执行脚本,请使用 dump 方法替代。
diff() {#collection-method}
diff 方法将集合与其它集合或者 PHP 数组进行值的比较。然后返回原集合中存在而指定集合中不存在的值:
$collection = collect([1, 2, 3, 4, 5]);
$diff = $collection->diff([2, 4, 6, 8]);
$diff->all();
// [1, 3, 5]{tip} 这个方法的行为当使用Eloquent Collections时会被重写。
diffAssoc() {#collection-method}
diffAssoc 方法与另外一个集合或基于 PHP 数组的键 / 值对(keys and values)进行比较。这个方法将会返回原集合不存在于指定集合的键 / 值对:
$collection = collect([
'color' => 'orange',
'type' => 'fruit',
'remain' => 6
]);
$diff = $collection->diffAssoc([
'color' => 'yellow',
'type' => 'fruit',
'remain' => 3,
'used' => 6,
]);
$diff->all();
// ['color' => 'orange', 'remain' => 6]
diffKeys() {#collection-method}
diffKeys方法和另外一个集合或 PHP 数组的键(keys)进行比较,然后返回原集合中存在而指定集合中不存在键所对应的键 / 值对:
$collection = collect([
'one' => 10,
'two' => 20,
'three' => 30,
'four' => 40,
'five' => 50,
]);
$diff = $collection->diffKeys([
'two' => 2,
'four' => 4,
'six' => 6,
'eight' => 8,
]);
$diff->all();
// ['one' => 10, 'three' => 30, 'five' => 50]
dump() {#collection-method}
dump 方法用于打印集合项:
$collection = collect(['John Doe', 'Jane Doe']);
$collection->dump();
/*
Collection {
#items: array:2 [
0 => "John Doe"
1 => "Jane Doe"
]
}
*/
如果要在打印集合后终止执行脚本,请使用 dd 方法代替。
duplicates() {#collection-method}
duplicates 方法从集合中检索并返回重复的值:
$collection = collect(['a', 'b', 'a', 'c', 'b']);
$collection->duplicates();
// [2 => 'a', 4 => 'b']
如果集合包含数组或对象,则可以传递希望检查重复值的属性的键:
$employees = collect([
['email' => 'abigail@example.com', 'position' => 'Developer'],
['email' => 'james@example.com', 'position' => 'Designer'],
['email' => 'victoria@example.com', 'position' => 'Developer'],
])
$employees->duplicates('position');
// [2 => 'Developer']
duplicatesStrict() {#collection-method}
此方法与 duplicates 方法具有相同的签名;但是,所有值都以「严格」的方式进行比较。
each() {#collection-method}
each 方法用于循环集合项并将其传递到回调函数中:
$collection->each(function ($item, $key) {
//
});
如果你想中断对集合项的循环,那么就在你的回调函数中返回 false :
$collection->each(function ($item, $key) {
if (/* some condition */) {
return false;
}
});
eachSpread() {#collection-method}
eachSpread 方法用于循环集合项,将每个嵌套集合项的值传递给回调函数:
$collection = collect([['John Doe', 35], ['Jane Doe', 33]]);
$collection->eachSpread(function ($name, $age) {
//
});
你可以通过在回调函数里返回 false 来中断循环:
$collection->eachSpread(function ($name, $age) {
return false;
});
every() {#collection-method}
every 方法可用于验证集合中的每一个元素是否通过指定的条件测试:
collect([1, 2, 3, 4])->every(function ($value, $key) {
return $value > 2;
});
// false
如果集合为空, every 将返回 true :
$collection = collect([]);
$collection->every(function ($value, $key) {
return $value > 2;
});
// true
except() {#collection-method}
except 方法返回集合中除了指定键之外的所有集合项:
$collection = collect(['product_id' => 1, 'price' => 100, 'discount' => false]);
$filtered = $collection->except(['price', 'discount']);
$filtered->all();
// ['product_id' => 1]
与 except 对应的是only方法。
{tip} 这个方法的行为当使用 Eloquent Collections时会被重写。
filter() {#collection-method}
filter 方法使用给定的回调函数过滤集合,只保留那些通过指定条件测试的集合项:
$collection = collect([1, 2, 3, 4]);
$filtered = $collection->filter(function ($value, $key) {
return $value > 2;
});
$filtered->all();
// [3, 4]
如果没有提供回调函数,集合中所有返回 false 的元素都会被移除:
$collection = collect([1, 2, 3, null, false, '', 0, []]);
$collection->filter()->all();
// [1, 2, 3]
filter 对应的是reject方法。
first() {#collection-method}
first 方法返回集合中通过指定条件测试的第一个元素:
collect([1, 2, 3, 4])->first(function ($value, $key) {
return $value > 2;
});
// 3
你也可以不传入参数调用 first 方法来获取集合中的第一个元素。如果集合为空,则会返回 null :
collect([1, 2, 3, 4])->first();
// 1
firstWhere()
firstWhere 方法返回集合中含有指定键 / 值对的第一个元素:
$collection = collect([
['name' => 'Regena', 'age' => null],
['name' => 'Linda', 'age' => 14],
['name' => 'Diego', 'age' => 23],
['name' => 'Linda', 'age' => 84],
]);
$collection->firstWhere('name', 'Linda');
// ['name' => 'Linda', 'age' => 14]
你也可以使用运算符来调用 firstWhere 方法:
$collection->firstWhere('age', '>=', 18);
// ['name' => 'Diego', 'age' => 23]
和 where 方法一样,你可以将一个参数传递给 firstWhere 方法。在这种情况下, firstWhere 方法将返回指定键的值为「真」的第一个集合项:
$collection->firstWhere('age');
// ['name' => 'Linda', 'age' => 14]
flatMap()
flatMap 方法遍历集合并将其中的每个值传递到给定的回调函数。可以通过回调函数修改集合项并返回它们,从而形成一个被修改过的新集合。然后,集合转化的数组是同级的:
$collection = collect([
['name' => 'Sally'],
['school' => 'Arkansas'],
['age' => 28]
]);
$flattened = $collection->flatMap(function ($values) {
return array_map('strtoupper', $values);
});
$flattened->all();
// ['name' => 'SALLY', 'school' => 'ARKANSAS', 'age' => '28'];
flatten()
flatten 方法将多维集合转为一维集合:
$collection = collect(['name' => 'taylor', 'languages' => ['php', 'javascript']]);
$flattened = $collection->flatten();
$flattened->all();
// ['taylor', 'php', 'javascript'];
你可以选择性地传入「深度」参数:
$collection = collect([
'Apple' => [
['name' => 'iPhone 6S', 'brand' => 'Apple'],
],
'Samsung' => [
['name' => 'Galaxy S7', 'brand' => 'Samsung']
],
]);
$products = $collection->flatten(1);
$products->values()->all();
/*
[
['name' => 'iPhone 6S', 'brand' => 'Apple'],
['name' => 'Galaxy S7', 'brand' => 'Samsung'],
]
*/
在这个例子里,调用 flatten 时不传入深度参数的话也会将嵌套数组转成一维的,然后返回 ['iPhone 6S', 'Apple', 'Galaxy S7', 'Samsung'] 。传入深度参数能让你限制设置返回数组的层数。
flip()
flip 方法将集合的键和对应的值进行互换:
$collection = collect(['name' => 'taylor', 'framework' => 'laravel']);
$flipped = $collection->flip();
$flipped->all();
// ['taylor' => 'name', 'laravel' => 'framework']
forget()
forget 方法将通过指定的键来移除集合中对应的内容:
$collection = collect(['name' => 'taylor', 'framework' => 'laravel']);
$collection->forget('name');
$collection->all();
// ['framework' => 'laravel']注意:与大多数集合的方法不同的是, forget 不会返回修改后的新集合;它会直接修改原集合。
forPage()
forPage 方法返回一个含有指定页码数集合项的新集合。这个方法接受页码数作为其第一个参数,每页显示的项数作为其第二个参数:
$collection = collect([1, 2, 3, 4, 5, 6, 7, 8, 9]);
$chunk = $collection->forPage(2, 3);
$chunk->all();
// [4, 5, 6]
get()
get 方法返回指定键的集合项,如果该键在集合中不存在,则返回 null:
$collection = collect(['name' => 'taylor', 'framework' => 'laravel']);
$value = $collection->get('name');
// taylor
你可以任选一个默认值作为第二个参数传递:
$collection = collect(['name' => 'taylor', 'framework' => 'laravel']);
$value = $collection->get('foo', 'default-value');
// default-value
你甚至可以将一个回调函数作为默认值传递。如果指定的键不存在,就会返回回调函数的结果:
$collection->get('email', function () {
return 'default-value';
});
// default-value
groupBy()
groupBy 方法根据指定键对集合项进行分组:
$collection = collect([
['account_id' => 'account-x10', 'product' => 'Chair'],
['account_id' => 'account-x10', 'product' => 'Bookcase'],
['account_id' => 'account-x11', 'product' => 'Desk'],
]);
$grouped = $collection->groupBy('account_id');
$grouped->toArray();
/*
[
'account-x10' => [
['account_id' => 'account-x10', 'product' => 'Chair'],
['account_id' => 'account-x10', 'product' => 'Bookcase'],
],
'account-x11' => [
['account_id' => 'account-x11', 'product' => 'Desk'],
],
]
*/
你可以传递一个回调函数用来代替一个字符串的 键。这个回调函数应该返回你希望用来分组的键的值:
$grouped = $collection->groupBy(function ($item, $key) {
return substr($item['account_id'], -3);
});
$grouped->toArray();
/*
[
'x10' => [
['account_id' => 'account-x10', 'product' => 'Chair'],
['account_id' => 'account-x10', 'product' => 'Bookcase'],
],
'x11' => [
['account_id' => 'account-x11', 'product' => 'Desk'],
],
]
*/
可以传递一个数组用于多重分组标准。每一个数组元素将对应多维数组内的相应级别:
$data = new Collection([
10 => ['user' => 1, 'skill' => 1, 'roles' => ['Role_1', 'Role_3']],
20 => ['user' => 2, 'skill' => 1, 'roles' => ['Role_1', 'Role_2']],
30 => ['user' => 3, 'skill' => 2, 'roles' => ['Role_1']],
40 => ['user' => 4, 'skill' => 2, 'roles' => ['Role_2']],
]);
$result = $data->groupBy([
'skill',
function ($item) {
return $item['roles'];
},
], $preserveKeys = true);
/*
[
1 => [
'Role_1' => [
10 => ['user' => 1, 'skill' => 1, 'roles' => ['Role_1', 'Role_3']],
20 => ['user' => 2, 'skill' => 1, 'roles' => ['Role_1', 'Role_2']],
],
'Role_2' => [
20 => ['user' => 2, 'skill' => 1, 'roles' => ['Role_1', 'Role_2']],
],
'Role_3' => [
10 => ['user' => 1, 'skill' => 1, 'roles' => ['Role_1', 'Role_3']],
],
],
2 => [
'Role_1' => [
30 => ['user' => 3, 'skill' => 2, 'roles' => ['Role_1']],
],
'Role_2' => [
40 => ['user' => 4, 'skill' => 2, 'roles' => ['Role_2']],
],
],
];
*/