
Javascript: Synchronous imports
Recently we’ve come across a challenge. Well not really a challenge for normal developers, but one for developers that like […]
Read moreBeing a programmer, you’re probably very (very) familiar with the for
and foreach
loops in PHP and Javascript. So familiar in fact, that you’re kind of resenting them whenever you need to create a subset from a set
.
We’re here to tell you that there’s more to the world than just foreach
-ing. Introducing: map
and filter
Let’s imagine we have a set of data as such
$books = [
[
"id" => 1,
"title" => "1984",
"author" => "George Orwell"
],
[
"id" => 2,
"title" => "To Kill a Mockingbird",
"author" => "Harper Lee"
],
[
"id" => 3,
"title" => "The Great Gatsby",
"author" => "F. Scott Fitzgerald"
],
[
"id" => 4,
"title" => "One Hundred Years of Solitude",
"author" => "Gabriel García Márquez"
]
];
Let’s say we only want to get the uneven
id
‘s from this list. Normally you would do something like this:
// create a new array to contain our filtered books
$filteredBooks = [];
// iterate over each book
foreach ($books as $book) {
// check if the id is not divisible by 2
if ($book['id'] % 2) {
// add the book to the filtered books
$filteredBooks[] = $book;
}
}
// output the filtered books
foreach ($filteredBooks as $filteredBook) {
echo $filteredBook['id'] . "\n";
}
The above example is basically how “anyone” would create a subset
in PHP.
However, there is a much faster (and cleaner) way of writing the above. Using a method called array_filter
we can directly create a subset
without having to declare
a separate variable before filtering
our set.
// declare filteredBooks based on the results of array_filter
$filteredBooks = array_filter($books, function ($book) {
// return a boolean indicating if the id is not divisible by 2
return $book['id'] % 2;
});
foreach ($filteredBooks as $filteredBook) {
echo $filteredBook['id'] . "\n";
}
Much cleaner right? The array_filter
method relies on the “boolean result, returned by it’s closure”, meaning it filters any “false” result.
In this scenario we want to do something else completly. We just want the title
from each book
in our books
set. That’s easy right? You’ll probably write something like the following:
// declare a new array to contain our titles
$titles = [];
// iterate over each book
foreach ($books as $book) {
// get the title and add it to our titles array
$titles[] = $book["title"];
}
// output the titles
foreach ($titles as $title) {
echo $title . "\n";
}
If you’re anything like us, you’ll probably get this gnawing feeling that this method seems… too much. Even overkill perhaps. You’re right.
Just like array_filter
is a good method to create subsets, the array_map
function excels at basically “remapping” an array. To use array_map
we could do the following:
// declare titles based on the result of array_map
$titles = array_map(function ($book) {
// return the book's title
return $book['title'];
}, $books);
foreach ($titles as $title) {
echo $title . "\n";
}
In this scenario, it might seem excessive to use an array_map
because we could just iterate
over the original set right? Well, that’s why we’re going to combine both:
Using what we learnt above, we could combine our knowledge to do some very cool things.
Let’s say you would like to get all author
‘s from the books
set where the title
contains the letter a
. We could achieve this by first using array_filter
to create a subset
and then map
the author
‘s.
Normally in PHP that would look something like this:
// create a new array to contain our filtered books
$filteredBooks = [];
// iterate over each book
foreach ($books as $book) {
// check if the title contains the letter 'a'
if (strpos($book['title'], 'a') > -1) {
// add the book to the filtered books
$filteredBooks[] = $book;
}
}
$authors = [];
foreach ($filteredBooks as $filteredBook) {
$authors[] = $filteredBook['author'];
}
Or if you’re slightly more experience you would probably do this using only one iteration:
// create a new array to contain our filtered books
$authors = [];
// iterate over each book
foreach ($books as $book) {
// check if the title contains the letter 'a'
if (strpos($book['title'], 'a') > -1) {
// add the author to the authors
$authors[] = $book['author'];
}
}
// output the authors
foreach ($authors as $author) {
echo $author . "\n";
}
This still feels kinda “yucky” right? We agree. So here’s how we would do it:
// this blocks reads from bottom to top because results as chained
// declare authors containing the result from array_map
$authors = array_map(function ($book) {
// return the book's author
return $book['author'];
// use the subset from array_filter as the argument for array_map
}, array_filter($books, function ($book) {
// return a boolean indicated the book's title contains the letter 'a'
return strpos($book['title'], 'a') > -1;
}));
// output the authors
foreach ($authors as $author) {
echo $author . "\n";
}
Because array_map
accepts an array
as an argument, and array_filter
returns an array
, we can “chain” these functions using their respective outputs.
The functions array_map
and array_filter
are very useful, especially when combined. The drawback to chaining these functions like in Scenario 3, is that they might become “unreadable” for inexperienced programmers.
However, mastering these (and other functions like array_reduce
, array_intersect
, etc) will make life a lot easier for you in the long run. These functions also use internal libraries
to speed up their execution, so if you’re iterating over massive collections, this is the way to go.
Recently we’ve come across a challenge. Well not really a challenge for normal developers, but one for developers that like […]
Read moreSo we’ve come across plenty of posts comparing / measuring performance of the PHP array_map function vs foreach. So we […]
Read more
Leave a Reply