thinkingmedia / underscore
Underscore is a PHP library that provides useful helpers when working with arrays and collections.
Requires
- php: >=5.4.0
- symfony/property-access: ~2.0
This package is not auto-updated.
Last update: 2024-10-26 17:13:43 UTC
README
Underscore
is an utility library that makes working with arrays in PHP
a little bit more pleasant.
Installation
Via Composer
$ composer require thinkingmedia/underscore
Usage
The following examples assume that you have included the Underscore utility:
use Underscore\_;
Some of the examples might seem a bit contrived, but they're actually really handy. For example, let's say that we have a fictional social network and (for some reason) we want to get the names of all the authenticated user's 2nd degree friends (friends-of-friends) that are over the age of 18. Suddenly, that becomes real easy!
_::create($user->getFriends())->map(function ($f) { return $f->getFriends(); })->select(function ($f) { return $f->getAge() > 18; })->pluck('username');
And now (for some even stranger reason) we want to know the total number of third degree friends (friends-of-friends-of-friends) of the 2nd degree friends that are over the age of 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()); });
That's it!
Note: When, in the examples, the return value comment indicates an array the actual return value is a new
_
instance! You can get the actual PHP array value by calling thetoArray
method.
The _
class implements ArrayAccess
too, so you can access it like an usual array:
$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
Additionally, you can traverse the container in a foreach
loop as well:
$users = _::create(['alice', 1337, 'bob', 42])->chunk(2); foreach ($users as $name => $karma) { // ... }
all
Call the given callback
for each element in the container. Should the callback
return false
, the method immediately returns false
and ceases enumeration.
If all invocations of the callback return true
, all
returns true
.
_::create([1, 2, 3])->all(function ($n) { return $n > 0; }); // true
any
Call the given callback
for each element in the container. Should the callback
return true
, the method immediately returns true
and enumeration is ceased.
If all invocations of the callback return false
, any
returns false
.
_::create([1, 2, 3])->any(function ($n) { return $n > 2; }); // true
chunk
Chunks the container into a new array of n
-sized chunks.
_::create([1, 2, 3, 4])->chunk(2); // [[1, 2], [3, 4]]
combine
Combine the container with another array into key/value pairs.
_::create([1, 2, 3])->combine(['foo', 'bar', 'baz']); // [1 => 'foo', 2 => 'bar', 3 => 'baz']
concat
Returns a new array that is the container with the given array
concatenated
to the end.
_::create([1, 2])->concat([3, 4]); // [1, 2, 3, 4]
dict
Convert an array of key/value pairs into the logical dictionary.
_::create([[1, 2], [3, 4]])->dict(); // [1 => 2, 3 => 4]
If you have a flat array you can call chunk(2)
before dict
.
_::create([1, 2, 3, 4])->chunk(2)->dict(); // [1 => 2, 3 => 4]
each
Calls the given callback once for each element in the container, passing that element as the argument.
_::create([1, 2, 3, 4])->each(function ($n) { printf("%d\n", $n); }); // outputs: 1\n2\n3\n4\n
each
also supports two and three parameter versions:
_::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
Passes each entry in the container to the given callback, returning the first
element for which callback is not false
. If no entry matches, returns null
.
_::create([1, 2, 3, 4])->find(function ($n) { return $n > 2; }); // 3
first
Returns the first n
elements in the container.
_::create([1, 2, 3, 4])->first(2); // [1, 2]
flatten
Returns a new, one-dimensional array that is a recursive flattening of the container.
_::create([1, [2], [3, [4]]])->flatten(); [1, 2, 3, 4]
Tip: If you only want to flatten one level of an array,
flatMap
might be useful for you!
flatMap
Returns a new array with the concatenated results of invoking the callback once for every element in the container.
_::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]]
It might look a bit silly, but this is actually a really useful function when you combine it with other functions! For example, you can create a dictionary for (fictional) users.
_::create([new User('bob', 32), new User('alice', 35)])->flatMap(function ($u) { return [$n->getName(), $n->getAge()]; })->chunk(2)->dict(); // ['bob' => 32, 'alice' => 35]
Which finally allows us, as developers, to create key/value pairs when mapping arrays! Hoorah!
groupBy
Groups the container by result of the given callback.
_::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
Returns the index of the given object in the container or null
if the element
was not found.
_::create([1, 2, 3, 4])->indexOf(2); // 1 _::create([1, 2, 3, 4])->indexOf(0); // null
inject
Combines all elements of the container by applying a binary operation.
_::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
Note: This is the only exception to the note earlier. The return value here is the return value of the last itertation.
join
Returns a string of all the container's elements joined with the provided separator string.
_::create([1, 2, 3, 4])->join(''); // 1234 _::create([1, 2, 3, 4])->join(','); // 1,2,3,4
last
Returns the last n
elements from the container.
_::create([1, 2, 3, 4, 5, 6])->last(2); // [5, 6]
map
Invokes the given callback for each element in the container. Creates a new array containing the values returned by the block.
If the given callback returns null
, that element is skipped in the returned
array.
_::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
Returns the element for which the given callback returns the largest integer.
_::create('1', 'two', 'three')->max(function ($s) { return strlen($s); }); // 'three'
min
Returns the element for which the given callback returns the smallest integer.
_::create('1', 'two', 'three')->min(function ($s) { return strlen($s); }); // '1'
none
Test if the given callback returns false
for each element in the container.
_::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
Partitions the container into two arrays based on the boolean return value of the given block.
_::create(['A', 'B', 'C', 'AA'])->partition(function ($s) { return $s[0] == 'A'; }); // [['A', 'AA'], ['B', 'C']]
pluck
Returns a new array that is the result of retrieving the given property path on each element in the container.
_::create([new User('bob'), new User('alice')])->pluck('username'); // ['bob', 'alice']
product
Calculate the product of the container by assuming that all values can be casted to a double value.
_::create([1, 2, 3])->product(); // 6
reduce
Reduces the container to a single value.
The usual example of reduce is to sum all values in an array.
_::create([1, 2, 3, 4])->reduce(function ($memo, $n) { return $memo + $n; }); // 10
Reduce also allows you to set an initial value before reducing the array.
_::create([1, 2, 3, 4])->reduce(function ($s, $n) { return $s + $n; }, 10); // 20
reject
Returns a new array containing all elements for which the given callback
returns false
.
_::create([1, 2, 3, 4])->reject(function ($n) { return ($n % 2) == 0; }); // [1, 3]
reverse
Returns a new array that is the container, reversed.
_::create([1, 2, 3, 4])->reverse(); // [4, 3, 2, 1]
rotate
Returns a new array rotated about the provided index.
_::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
Returns a random element from the container.
_::create([1, 2, 3, 4, 5, 6])->sample(); // Basically a dice roll...
select
Returns a new array containing all elements for which the given block returns
true
.
_::create([1, 2, 3, 4])->select(function ($n) { return ($n % 2) == 0; }); // [2, 4]
shuffle
Returns a new array that is shuffled.
_::create([1, 2])->shuffle(); // Either [1, 2] or [2, 1]
skip
Skips the first n
elements and returns the rest of the array.
_::create([1, 2, 3, 4, 5, 6])->skip(2); // [3, 4, 5, 6]
slice
Returns a subarray consisting of the given number of elements from the given starting index.
_::create([1, 2, 3, 4])->slice(1, 2); // [2, 3]
snip
Snips the end off the array. Returns the container without the last n
elements.
_::create([1, 2, 3, 4, 5, 6])->snip(2); // [1, 2, 3, 4]
sort
Returns the container, sorted.
_::create([1, 4, 2, 3])->sort(); // [1, 2, 3, 4]
sortBy
Sorts all objects using the return value of the given callback as the sorting criteria.
$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
Sum all objects by casting the values to a double.
_::create([1, 2, 3, 4])->sum(); // 10
transpose
Assumes that the container is an array of arrays and transposes the rows and columns.
_::create([[1, 2, 3], [4, 5, 6]])->transpose(); // [[1, 4], [2, 5], [3, 6]]
uniq
Returns a new array by removing duplicate values in the container.
_::create([1, 2, 3, 1, 2, 4, 1, 2, 5])->uniq(); // [3, 4, 5]
without
Returns a new array where objects in the given array are removed from the container.
_::create([1, 2, 4, 3])->without([4]); // [1, 2, 3] _::create([1, 2, 3, 4, 5])->without([4, 5]); // [1, 2, 3]
pop
Treats container like a stack and removes the last object, returning it.
_::create()->push(1)->push(2)->push(3)->pop(); // 3
push
Treats container like a stack and adds the given object to the end of the container.
_::create()->push(1)->push(2)->push(3); // [1, 2, 3]
shift
Removes the container's first object and returns it.
_::create([1, 2, 3])->shift(); // 1
unshift
Inserts the given object at the front of container, moving all other objects in the container up one index.
_::create([2, 3])->unshift(1); // [1, 2, 3]
split
Returns a new array of the strings in the given string that are separated by the given separator.
_::split('foo bar baz', ' '); // ['foo', 'bar', 'baz']
The second parameter is optional and null
by default, if you pass null
or
an empty string as seperator, you will get an array of the individual characters
in the given string.
_::split('1234'); // ['1', '2', '3', '4']
We can do some pretty neat stuff with this!
_::split('1234')->sum(); // 10
first
, last
, skip
, snip
& slice
These functions are strongly related and useful to remember.
_::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]
Contributing
Please see CONTRIBUTING.
Credits
This project is heavily inspired by YOLOKit. For all of you who develop in Objective-C, I highly recommend you check it out!
License
Please see LICENSE.