thinkingmedia / underscore
Underscore 是一个 PHP 库,它提供了一些有用的辅助函数,以便在处理数组和集合时使用。
Requires
- php: >=5.4.0
- symfony/property-access: ~2.0
This package is not auto-updated.
Last update: 2024-09-28 16:36:22 UTC
README
Underscore
是一个实用库,可以使 PHP 中的数组操作更加愉快。
安装
通过 Composer
$ composer require thinkingmedia/underscore
用法
以下示例假设您已经包含了 Underscore 工具
use Underscore\_;
一些示例可能看起来有点牵强,但实际上非常实用。例如,假设我们有一个虚构的社交网络,并且(出于某种原因)我们想要获取所有通过认证的用户超过 18 岁的二级朋友(朋友的朋友)的姓名。突然,这变得容易多了!
_::create($user->getFriends())->map(function ($f) { return $f->getFriends(); })->select(function ($f) { return $f->getAge() > 18; })->pluck('username');
现在(出于更奇怪的原因),我们想知道所有二级朋友(朋友的朋友)超过 18 岁的第三级朋友的数量。
_::create($user->getFriends())->map(function ($f) { return $f->getFriends(); })->select(function ($f) { return $f->getAge() > 18; })->reduce(function ($s, $f) { return $s + count($f->getFriends()); });
就这些!
注意:在示例中,当返回值注释表明是一个数组时,实际的返回值是一个新的
_
实例!您可以通过调用toArray
方法来获取实际的 PHP 数组值。
_
类实现了 ArrayAccess
,因此您可以使用它像使用常规数组一样访问它
$groups = _::create($user->getFriends())->groupBy(function ($friend) { $name = $friend->getName(); return $name[0]; }); $groups['A'] = ...; // All friends with the letter 'A' as the first letter in their name
此外,您还可以使用 foreach
循环遍历容器
$users = _::create(['alice', 1337, 'bob', 42])->chunk(2); foreach ($users as $name => $karma) { // ... }
all
为容器中的每个元素调用给定的 callback
。如果回调返回 false
,则方法立即返回 false
并停止枚举。如果所有回调调用都返回 true
,则 all
返回 true
。
_::create([1, 2, 3])->all(function ($n) { return $n > 0; }); // true
any
为容器中的每个元素调用给定的 callback
。如果回调返回 true
,则方法立即返回 true
并停止枚举。如果所有回调调用都返回 false
,则 any
返回 false
。
_::create([1, 2, 3])->any(function ($n) { return $n > 2; }); // true
chunk
将容器分成一个新数组,该数组由大小为 n
的块组成。
_::create([1, 2, 3, 4])->chunk(2); // [[1, 2], [3, 4]]
combine
将容器与另一个数组合并成键/值对。
_::create([1, 2, 3])->combine(['foo', 'bar', 'baz']); // [1 => 'foo', 2 => 'bar', 3 => 'baz']
concat
返回一个新的数组,它是容器与给定 array
连接到末尾的结果。
_::create([1, 2])->concat([3, 4]); // [1, 2, 3, 4]
dict
将键/值对数组转换为逻辑字典。
_::create([[1, 2], [3, 4]])->dict(); // [1 => 2, 3 => 4]
如果您有一个扁平数组,可以在 dict
之前调用 chunk(2)
。
_::create([1, 2, 3, 4])->chunk(2)->dict(); // [1 => 2, 3 => 4]
each
为容器中的每个元素调用一次给定的回调,将元素作为参数传递。
_::create([1, 2, 3, 4])->each(function ($n) { printf("%d\n", $n); }); // outputs: 1\n2\n3\n4\n
each
也支持两种和三种参数版本
_::create([1, 2, 3, 4])->each(function ($n, $i) { printf("%d: %d\n", $i, $n); }); //outputs: 0: 1\n1: 2\n2: 3\n3: 4\n _::create([1, 2, 3, 4]->each(function ($n, $i, $array) { // ... }));
find
将容器中的每个条目传递给给定的回调,返回第一个回调不是 false
的元素。如果没有条目匹配,则返回 null
。
_::create([1, 2, 3, 4])->find(function ($n) { return $n > 2; }); // 3
first
返回容器中的前 n
个元素。
_::create([1, 2, 3, 4])->first(2); // [1, 2]
flatten
返回一个新的、一维数组,它是容器的递归展平。
_::create([1, [2], [3, [4]]])->flatten(); [1, 2, 3, 4]
提示:如果您只想展平数组的一级,则
flatMap
可能对您很有用!
flatMap
返回一个新的数组,它是调用回调一次为容器中的每个元素生成的结果的连接。
_::create([1, 2, 3, 4])->flatMap(function ($n) { return [$n, $n]; }); // [1, 1, 2, 2, 3, 3, 4, 4] _::create([1, 2, 3, 4])->flatMap(function ($n) { return [$n, [$n]]; }); // [1, [1], 2, [2], 3, [3], 4, [4]]
它看起来可能有点愚蠢,但这是一个非常有用的函数,当与其它函数结合使用时!例如,您可以创建(虚构的)用户的字典。
_::create([new User('bob', 32), new User('alice', 35)])->flatMap(function ($u) { return [$n->getName(), $n->getAge()]; })->chunk(2)->dict(); // ['bob' => 32, 'alice' => 35]
这最终允许我们作为开发者,在映射数组时创建键/值对!太棒了!
groupBy
按给定回调的结果对容器进行分组。
_::create([1, 2, 3, 4])->groupBy(function ($n) { return $n % 2; }); // [0 => [2, 4], 1 => [1, 3]] _::create(['foo', 'bar', 'baz'])->groupBy(function ($s) { return $s[0]; }); // ['f' => ['foo'], 'b' => ['bar', 'baz']]
has
_::create([1, 2, 3, 4])->has(2); // true _::create([1, 2, 3, 4])->has(0); // false
indexOf
返回给定对象在容器中的索引,如果元素未找到则返回null
。
_::create([1, 2, 3, 4])->indexOf(2); // 1 _::create([1, 2, 3, 4])->indexOf(0); // null
inject
通过应用二元运算符组合容器的所有元素。
_::create([1, 2, 3])->inject([], function ($m, $n) { $m[$n] = $n * $n; return $m; }); // [1 => 1, 2 => 4, 3 => 9] _::create(['foo', 'bar', 'baz'])->inject('', function ($m, $s) { $m .= $s; }); // foobarbaz
注意:这是之前提到的唯一例外。这里的返回值是最后一个迭代的结果。
join
返回一个字符串,该字符串将容器的所有元素与提供的分隔符字符串连接起来。
_::create([1, 2, 3, 4])->join(''); // 1234 _::create([1, 2, 3, 4])->join(','); // 1,2,3,4
last
返回容器中的最后n
个元素。
_::create([1, 2, 3, 4, 5, 6])->last(2); // [5, 6]
map
对容器中的每个元素执行给定的回调。创建一个新数组,包含块返回的值。
如果给定的回调返回null
,则返回数组中跳过该元素。
_::create([1, 2, 3, 4])->map(function ($n) { return $n * $n; }); // [1, 4, 9, 16] _::create([1, 2, 3, 4])->map(function ($n) { return $n % 2 ? $n * $n : null; }); // [1, 9]
max
返回给定回调返回最大整数的元素。
_::create('1', 'two', 'three')->max(function ($s) { return strlen($s); }); // 'three'
min
返回给定回调返回最小整数的元素。
_::create('1', 'two', 'three')->min(function ($s) { return strlen($s); }); // '1'
none
测试给定回调是否对容器中的每个元素都返回false
。
_::create([1, 2, 3, 4])->none(function ($n) { return $n < 0; }); // true _::create([1, 2, 3, 4])->none(function ($n) { return $n > 0; }); // false
partition
根据给定块返回的布尔值将容器分割成两个数组。
_::create(['A', 'B', 'C', 'AA'])->partition(function ($s) { return $s[0] == 'A'; }); // [['A', 'AA'], ['B', 'C']]
pluck
返回一个新数组,该数组是通过对容器中的每个元素获取给定属性路径的结果。
_::create([new User('bob'), new User('alice')])->pluck('username'); // ['bob', 'alice']
product
通过假设所有值都可以转换为double值来计算容器的乘积。
_::create([1, 2, 3])->product(); // 6
reduce
将容器减少到单个值。
reduce的常用示例是计算数组中所有值的总和。
_::create([1, 2, 3, 4])->reduce(function ($memo, $n) { return $memo + $n; }); // 10
Reduce还允许在减少数组之前设置一个初始值。
_::create([1, 2, 3, 4])->reduce(function ($s, $n) { return $s + $n; }, 10); // 20
reject
返回一个新数组,包含所有给定的回调返回false
的元素。
_::create([1, 2, 3, 4])->reject(function ($n) { return ($n % 2) == 0; }); // [1, 3]
reverse
返回一个新数组,该数组是容器的反转。
_::create([1, 2, 3, 4])->reverse(); // [4, 3, 2, 1]
rotate
返回一个新数组,该数组绕提供的索引旋转。
_::create([1, 2, 3, 4, 5, 6])->rotate(2); // [3, 4, 5, 6, 1, 2] _::create([1, 2, 3, 4, 5, 6])->rotate(-2); // [5, 6, 1, 2, 3, 4]
sample
从容器中返回一个随机元素。
_::create([1, 2, 3, 4, 5, 6])->sample(); // Basically a dice roll...
select
返回一个新数组,包含所有给定的块返回true
的元素。
_::create([1, 2, 3, 4])->select(function ($n) { return ($n % 2) == 0; }); // [2, 4]
shuffle
返回一个新数组,该数组已打乱顺序。
_::create([1, 2])->shuffle(); // Either [1, 2] or [2, 1]
skip
跳过前n
个元素并返回其余的数组。
_::create([1, 2, 3, 4, 5, 6])->skip(2); // [3, 4, 5, 6]
slice
返回一个子数组,该子数组从指定的起始索引开始,包含给定数量的元素。
_::create([1, 2, 3, 4])->slice(1, 2); // [2, 3]
snip
截断数组。返回不包含最后n
个元素的容器。
_::create([1, 2, 3, 4, 5, 6])->snip(2); // [1, 2, 3, 4]
sort
返回排序后的容器。
_::create([1, 4, 2, 3])->sort(); // [1, 2, 3, 4]
sortBy
使用给定的回调返回值作为排序标准对所有对象进行排序。
$rhombas = new Shape('rhombas'); $ellipse = new Shape('ellipse'); $hexagon = new Shape('hexagon'); _::create([ $rhombas, $ellipse, $hexagon ])->sortBy(function ($s) { return $s->getName(); }); // [ $ellipse, $hexagon, $rhombas ]
sum
通过将值转换为double来对对象进行求和。
_::create([1, 2, 3, 4])->sum(); // 10
transpose
假设容器是一个数组数组,并交换行和列。
_::create([[1, 2, 3], [4, 5, 6]])->transpose(); // [[1, 4], [2, 5], [3, 6]]
uniq
通过从容器中删除重复值返回一个新数组。
_::create([1, 2, 3, 1, 2, 4, 1, 2, 5])->uniq(); // [3, 4, 5]
without
返回一个新数组,其中从容器中删除了给定数组中的对象。
_::create([1, 2, 4, 3])->without([4]); // [1, 2, 3] _::create([1, 2, 3, 4, 5])->without([4, 5]); // [1, 2, 3]
pop
将容器视为栈,并移除最后一个对象,返回它。
_::create()->push(1)->push(2)->push(3)->pop(); // 3
push
将容器视为栈,并将给定的对象添加到容器的末尾。
_::create()->push(1)->push(2)->push(3); // [1, 2, 3]
shift
移除容器中的第一个对象并返回它。
_::create([1, 2, 3])->shift(); // 1
unshift
在容器的开头插入给定的对象,并将容器中的所有其他对象向上移动一个索引。
_::create([2, 3])->unshift(1); // [1, 2, 3]
split
返回一个新数组,该数组由给定字符串中的字符串组成,这些字符串通过给定的分隔符分隔。
_::split('foo bar baz', ' '); // ['foo', 'bar', 'baz']
第二个参数是可选的,默认值为null
。如果你传入null
或空字符串作为分隔符,你将得到一个包含给定字符串中各个字符的数组。
_::split('1234'); // ['1', '2', '3', '4']
我们可以用这个做很多很酷的事情!
_::split('1234')->sum(); // 10
first
,last
,skip
,snip
和slice
这些函数之间关系紧密,而且值得记住。
_::create([1, 2, 3, 4, 5])->first(2); // [1, 2] _::create([1, 2, 3, 4, 5])->last(2); // [4, 5] _::create([1, 2, 3, 4, 5])->skip(2); // [3, 4, 5] _::create([1, 2, 3, 4, 5])->snip(2); // [1, 2, 3] _::create([1, 2, 3, 4, 5])->slice(2, 2); // [3, 4]
贡献
请参阅贡献指南。
鸣谢
本项目深受YOLOKit的启发。对于那些使用Objective-C进行开发的开发者,我强烈推荐你们去看看!
许可证
请参阅许可证。