John Kary • @johnkary
Print numbers from 1 to 100, but...
For multiples of 3 print "Fizz"
For multiples of 5 print "Buzz"
For multiples of both 3 and 5 print "FizzBuzz"
$ php fizzbuzz.php
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
...
Buzz
foreach (range(1,100) as $num) {
$output = '';
if (0 === $num % 3) {
$output .= 'Fizz';
}
if (0 === $num % 5) {
$output .= 'Buzz';
}
if (!$output) {
$output = $num;
}
echo $output . "\n";
}
$max = 100;
$all = range(1, $max);
$threes = array_fill_keys(range(3, $max, 3), 'Fizz'); // [3 => 'Fizz', 6 => 'Fizz']
$fives = array_fill_keys(range(5, $max, 5), 'Buzz'); // [5 => 'Buzz', 10 => 'Buzz']
$fifteens = array_fill_keys(range(15, $max, 15), 'FizzBuzz'); // [15 => 'FizzBuzz']
echo join("\n", array_replace($all, $threes, $fives, $fifteens));
By Jeff Madsen @codebyjeff
What if we used arrays for (almost) everything?
Functional Programming
(defn encode
[#^InputStream input #^Writer output #^String alphabet line-length]
(let [buffer (make-array Byte/TYPE 3)]
(loop [line 0]
(let [len (.read input buffer)]
(when (pos? len)
(let [b0 (Integer/valueOf (int (aget buffer 0)))
b1 (Integer/valueOf (int (aget buffer 1)))
b2 (Integer/valueOf (int (aget buffer 2)))]
(cond (= len 3)
(let [s0 (bit-and 0x3F (bit-shift-right b0 2))
s1 (bit-and 0x3F
(bit-or (bit-shift-left b0 4)
(bit-shift-right b1 4)))
s2 (bit-and 0x3F
(bit-or (bit-shift-left b1 2)
(bit-shift-right b2 6)))
s3 (bit-and 0x3F b2)]
(.append output (.charAt alphabet s0))
(.append output (.charAt alphabet s1))
(.append output (.charAt alphabet s2))
(.append output (.charAt alphabet s3))))))))))
// array_map ( callable $callback , array $array1 [, array $... ] )
$start = [1, 2, 3, 4, 5];
$end = array_map(function ($i) {
return $i * 2;
}, $start);
// [2, 4, 6, 8, 10]
// array_filter ( array $array [, callable $callback [, int $flag = 0 ]] )
$start = [1, 2, 3, 4, 5, 6];
$even = array_filter($start, function ($i) {
return $i % 2 === 0;
});
// [2, 4, 6]
// array_reduce ( array $array , callable $callback [, mixed $initial = NULL ] )
$start = [1, 2, 3, 4, 5];
$end = array_reduce($start, function ($total, $i) {
return $total + $i;
}, 0);
// 15
$start = [1, 2, 3, 4, 5];
$end = [];
for ($i=0; $i < count($start); $i++) {
$current = $start[$i];
$end[] = $current * 2;
}
// $end [2, 4, 6, 8, 10]
$start = [1, 2, 3, 4, 5];
$end = array_map(function ($i) {
return $i * 2;
}, $start);
// $end [2, 4, 6, 8, 10]
$start = [1, 2, 3, 4, 5, 6];
$even = [];
foreach ($start as $i) {
if ($i % 2 === 0) {
$even[] = $i;
}
}
// $even [2, 4, 6]
$start = [1, 2, 3, 4, 5, 6];
$even = array_filter($start, function ($i) {
return $i %2 === 0;
});
// $even [2, 4, 6]
$start = [1, 2, 3, 4, 5];
$end = 0;
foreach ($start as $s) {
$end = $end + $s;
}
// $end === 15
$start = [1, 2, 3, 4, 5];
$end = array_reduce($start, function ($end, $i) {
return $end + $i;
}, 0);
// $end === 15
// $end = array_sum($start);
function sayHello($name) {
return 'Hello ' . $name;
}
echo sayHello("John"); // "Hello John"
class User {
public static function sayHello($name) {
return 'Hello ' . $name;
}
}
echo User::sayHello("John"); // "Hello John"
class User {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function sayHello() {
return 'Hello ' . $this->name;
}
}
$user = new User("John");
echo $user->sayHello(); // "Hello John"
$sayHello = function ($name) {
return 'Hello ' . $name;
};
echo $sayHello('John'); // "Hello John"
$method = "GET";
sayHello('John');
function sayHello($name) {
return 'Hello ' . $name . ' via ' . $method;
// PHP Notice: Undefined variable: method
}
$method = "GET";
sayHello('John');
// "Hello John via GET"
function sayHello($name) {
global $method;
return 'Hello ' . $name . ' via ' . $method;
}
$method = "GET";
function sayHello($name, $verb) {
return sprintf('Hello %s via %s', $name, $verb);
}
echo sayHello('John', $method); // "Hello John via GET"
function sayHello($name) {
return 'Hello ' . $name;
}
sayHello('John'); // "Hello John"
echo $name;
// `PHP Notice: Undefined variable: name ...`
// because $name is not accessible in enclosing scope
$method = "GET";
$greeting = function($name) use ($method) {
return sprintf('Hello %s via %s', $name, $method);
};
echo $greeting('John'); // "Hello John via GET"
for ($i = 0, $for_max = count($cached_inserts); $i < $for_max; $i++) {
if ($smarty->debugging) {
$_params = array();
require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
}
$args = unserialize($insert_args[$i]); $name = $args['name'];
if (isset($args['script'])) {
if(!smarty_core_get_php_resource($_params, $smarty)) {
return false;
}
$php_resource = $_params['php_resource'];
if ($resource_type == 'file') {
$smarty->_include($php_resource, true);
} else {
$smarty->_eval($php_resource);
}
}
$params['results'] = substr_replace($params['results'], $replace, strpos($params['results'], $cached_inserts[$i]), strlen($cached_inserts[$i]));
if ($smarty->debugging) {
$_params = array();
require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
$smarty->_smarty_debug_info[] = array('type' => 'insert',
'exec_time' => smarty_core_get_microtime($_params, $smarty) - $debug_start_time);
}
}
return $params['results'];
for ($i = 0, $for_max = count($cached_inserts); $i < $for_max; $i++) {
function doComplicatedThing() {
for ($i = 0, $for_max = count($cached_inserts); $i < $for_max; $i++) {
if ($smarty->debugging) {
$_params = array();
require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
}
$args = unserialize($insert_args[$i]); $name = $args['name'];
if (isset($args['script'])) {
if(!smarty_core_get_php_resource($_params, $smarty)) {
return false;
}
$php_resource = $_params['php_resource'];
if ($resource_type == 'file') {
$smarty->_include($php_resource, true);
} else {
$smarty->_eval($php_resource);
}
}
$params['results'] = substr_replace($params['results'], $replace, strpos($params['results'], $cached_inserts[$i]), strlen($cached_inserts[$i]));
if ($smarty->debugging) {
$_params = array();
require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
$smarty->_smarty_debug_info[] = array('type' => 'insert',
'exec_time' => smarty_core_get_microtime($_params, $smarty) - $debug_start_time);
}
}
return $params['results'];
}
$users = User::all();
foreach ($users as $user) {
if (is_admin($user)) {
echo "ID: " . $user->id . " Name: " . $user->name . "
";
foreach ($user->groups as $group) {
if (!in_array($group->admin, $users)) {
continue;
}
echo "Group Admin: " . $user->name . "
";
}
} else {
foreach ($user->activities as $activity) {
echo "Activities: ";
if ($activity->isActive()) {
echo $activity->name . "
";
}
}
}
}
foreach (...) {
if (...) {
foreach (...) {
if (...) {
// ...
}
}
} else {
foreach (...) {
if (...) {
// ...
}
}
}
}
$customFieldValues = $this->getRequestParam("customFieldValues");
if ($customFieldValues) {
foreach ($customFieldValues as $custValueInfo) {
$valueEntry = $reservation->getCustomFieldValueEntry($custValueInfo['id']);
// Not found, this is the first time they're setting the value, so we need
// to create a new entry
if (!$valueEntry) {
$customField = $resource->getCustomField($custValueInfo['id']);
if (!$customField) {
throw new \InvalidArgumentException("Attempted to set a custom field that does not belong to the specified Resource");
}
$valueEntry = new ReservationCustomFieldValueEntry();
$valueEntry->setField($customField);
$reservation->addCustomFieldValue($valueEntry);
}
$valueEntry->setValue($custValueInfo['value']);
}
}
public function getOldestStudentAction(Request $request) {
$method = $request->getMethod();
if ($method !== 'PUT') {
throw new \BadRequestMethod('Endpoint only accepts PUT requests');
}
$db = $this->getDatabase()->getConnection();
$roster = $db->query('Roster', $request->get('roster_id'));
$oldest = null;
foreach ($roster->getStudents() as $student) {
if (!$oldest || $student->getAge() > $oldest->getAge()) {
$oldest = $student;
}
}
$oldestName = $oldest->getName();
echo "The oldest student is " . $oldestName . "\n";
$db->close();
$roster->updateLastAccess();
// $method, $db, $roster, $request, $oldest, $student, $oldestName
}
$method = $request->getMethod();
if ($method !== 'POST') {
// ...
}
if ($request->getMethod() !== 'POST') {
// ...
}
$db = $this->getDatabase();
$conn = $db->getConnection();
$roster = $conn->query('Roster', $request->get('roster_id'));
$roster = $this
->getDatabase()
->getConnection()
->query('Roster', $request->get('roster_id'));
// 1. Multiply by 2
// 2. Remove any results over 9
// 3. Add numbers together
$start = [1, 2, 3, 4, 5];
echo array_reduce(array_filter(array_map(function ($i) {
return $i * 2;
}, $start), function ($i) {
return $i < 9;
}), function ($sum, $i) {
return $sum + $i;
}, 0);
// 20
array_map($fn, $array, [$...])
array_filter($array, $fn)
array_reduce($array, $fn, $initial)
$friends = ['John', 'Chris', 'Penelope', 'Megan'];
echo join(", ", addGreeting(keepUnderLength(6, $friends)));
// "Hello John, Hello Chris, Hello Megan"
$friends = ['John', 'Chris', 'Penelope', 'Megan'];
$short = keepUnderLength(6, $friends);
$greeted = addGreeting($short);
$result = join(", ", $greeted);
echo $result; // "Hello John, Hello Chris, Hello Megan"
$ cat friends.txt
John
Chris
Penelope
Megan
$ cat friends.txt | awk 'length($0) < 6'
John
Chris
Megan
$ cat friends.txt | awk 'length($0) < 6' | xargs -L1 echo "Hello"
Hello John
Hello Chris
Hello Megan
c/o Samantha Quiñones, "Building Real-Time Metric Pipelines"
$friends = new \Haystack\HArray(['John', 'Chris', 'Penelope', 'Megan']);
$greetings = $friends->filter(...)->map(...)->toArray();
// ["Hello John", "Hello Chris", "Hello Megan"]
class HArray extends \ArrayObject
{
private $array = [];
public function __construct(array $a = []) {
$this->array = $a;
}
public function map(callable $func) {
return new static(array_map($func, $this->array));
}
public function filter(callable $func = null) {
return new static(array_filter($this->array, $func));
}
public function reduce(callable $func, $initial = null) {
return array_reduce($this->array, $func, $initial);
}
}
$friends = new \Haystack\HArray(['John', 'Chris', 'Penelope', 'Megan']);
$greetings = $friends
->filter(...)
->filter(...)
->map(...)
->reduce(...)
->toArray();
return $greetings;
$friends = new \Haystack\HArray(['John', 'Chris', 'Penelope', 'Megan']);
$greetings = $friends
->filter(function ($name) {
return ...
})
->filter(function ($name) {
return ...
})
->map(function ($name) {
return ...
})
->reduce(function ($name) {
return ...
})
->toArray();
return $greetings;
get('story.json')
.then(function(response) {
return JSON.parse(response);
})
.then(function(response) {
console.log("Yey JSON!", response);
});
// 1. Multiply by 2
// 2. Remove any results over 9
// 3. Add numbers together
$start = [1, 2, 3, 4, 5];
echo (new \Haystack\HArray($start))
->map(function ($i) {
return $i * 2;
})
->filter(function ($i) {
return $i < 9;
})
->reduce(function ($sum, $i) {
return $sum + $i;
});
// 20
$ tree /projects/loops/src
src
└── FizzBuzz
├── Canonical.php class Canonical {}
├── Haystack.php class Haystack {}
└── SomeInterface.php interface SomeInterface {}
kataProvider('FizzBuzz');
// [ "\\RethinkingLoops\\FizzBuzz\\Canonical",
// "\\RethinkingLoops\\FizzBuzz\\Haystack" ]
function kataProvider($dir) {
$src = realpath(__DIR__ . '/../src/' . $dir);
$classes = [];
foreach (scandir($src) as $filename) {
// [ ".",
// "..",
// "Canonical.php",
// "Haystack.php",
// "SomeInterface.php" ]
}
return $classes;
}
function kataProvider($dir) {
$src = realpath(__DIR__ . '/../src/' . $dir);
$classes = [];
foreach (scandir($src) as $filename) {
$path = sprintf('%s/%s', $src, $filename);
// [
// "/projects/loops/src/FizzBuzz/.",
// "/projects/loops/src/FizzBuzz/..",
// "/projects/loops/src/FizzBuzz/Canonical.php",
// "/projects/loops/src/FizzBuzz/Haystack.php",
// "/projects/loops/src/FizzBuzz/SomeInterface.php",
// ]
}
return $classes;
}
function kataProvider($dir) {
$src = realpath(__DIR__ . '/../src/' . $dir);
$classes = [];
foreach (scandir($src) as $filename) {
$path = sprintf('%s/%s', $src, $filename);
if (false === is_dir($path)) {
// [
// "/projects/loops/src/FizzBuzz/Canonical.php",
// "/projects/loops/src/FizzBuzz/Haystack.php",
// "/projects/loops/src/FizzBuzz/SomeInterface.php",
// ]
}
}
return $classes;
}
function kataProvider($dir) {
$src = realpath(__DIR__ . '/../src/' . $dir);
$classes = [];
foreach (scandir($src) as $filename) {
$path = sprintf('%s/%s', $src, $filename);
if (false === is_dir($path)) {
$path = str_replace('.php', '', $path);
// [
// "/projects/loops/src/FizzBuzz/Canonical",
// "/projects/loops/src/FizzBuzz/Haystack",
// "/projects/loops/src/FizzBuzz/SomeInterface",
// ]
}
}
return $classes;
}
function kataProvider($dir) {
$src = realpath(__DIR__ . '/../src/' . $dir);
$classes = [];
foreach (scandir($src) as $filename) {
$path = sprintf('%s/%s', $src, $filename);
if (false === is_dir($path)) {
$path = str_replace('.php', '', $path);
$fqcn = str_replace($src . '/', '\\RethinkingLoops\\' . $dir . '\\', $path);
// [
// "\\RethinkingLoops\\FizzBuzz\\Canonical",
// "\\RethinkingLoops\\FizzBuzz\\Haystack",
// "\\RethinkingLoops\\FizzBuzz\\SomeInterface",
// ]
}
}
return $classes;
}
function kataProvider($dir) {
$src = realpath(__DIR__ . '/../src/' . $dir);
$classes = [];
foreach (scandir($src) as $filename) {
$path = sprintf('%s/%s', $src, $filename);
if (false === is_dir($path)) {
$path = str_replace('.php', '', $path);
$fqcn = str_replace($src . '/', '\\RethinkingLoops\\' . $dir . '\\', $path);
$r = new \ReflectionClass($fqcn);
if (false === $r->isAbstract()) {
$classes[] = $fqcn;
}
// [ "\\RethinkingLoops\\FizzBuzz\\Canonical",
// "\\RethinkingLoops\\FizzBuzz\\Haystack" ]
}
}
return $classes;
}
function kataProvider($dir) {
$src = realpath(__DIR__ . '/../src/' . $dir);
$classes = [];
foreach (scandir($src) as $filename) {
$path = sprintf('%s/%s', $src, $filename);
if (false === is_dir($path)) {
$path = str_replace('.php', '', $path);
$fqcn = str_replace($src . '/', '\\RethinkingLoops\\' . $dir . '\\', $path);
$r = new \ReflectionClass($fqcn);
if (false === $r->isAbstract()) {
$classes[] = $fqcn;
// $dir, $src, $classes, $filename, $path, $fqcn, $r
}
}
}
return $classes;
}
function kataProvider($dir) {
$src = realpath(__DIR__ . '/../src/' . $dir);
$paths = array_map(function ($filename) use ($src) {
return sprintf('%s/%s', $src, $filename);
}, scandir($src));
$files = array_filter($paths, function ($path) {
return false === is_dir($path);
});
$allClasses = array_map(function ($path) use ($src, $dir) {
$path = str_replace('.php', '', $path);
return str_replace($src . '/', '\\RethinkingLoops\\' . $dir . '\\', $path);
}, $files);
return array_filter($allClasses, function ($class) {
return false === (new \ReflectionClass($fqcn))->isAbstract();
});
}
function kataProvider($dir) {
$src = realpath(__DIR__ . '/../src/' . $dir);
return (new \Haystack\HArray(scandir($src)))
// [
// ".",
// "..",
// "Canonical.php",
// "Haystack.php",
// "SomeInterface.php",
// ]
}
function kataProvider($dir)
{
$src = realpath(__DIR__ . '/../src/' . $dir);
return (new \Haystack\HArray(scandir($src)))
->map(function ($filename) use ($src) {
return sprintf('%s/%s', $src, $filename);
})
// [
// "/projects/loops/src/FizzBuzz/.",
// "/projects/loops/src/FizzBuzz/..",
// "/projects/loops/src/FizzBuzz/Canonical.php",
// "/projects/loops/src/FizzBuzz/Haystack.php",
// "/projects/loops/src/FizzBuzz/SomeInterface.php",
// ]
}
function kataProvider($dir) {
$src = realpath(__DIR__ . '/../src/' . $dir);
return (new \Haystack\HArray(scandir($src)))
->map(function ($filename) use ($src) {
return sprintf('%s/%s', $src, $filename);
})
->filter(function ($path) {
return false === is_dir($path);
})
// [
// "/projects/loops/src/FizzBuzz/Canonical.php",
// "/projects/loops/src/FizzBuzz/Haystack.php",
// "/projects/loops/src/FizzBuzz/SomeInterface.php",
// ]
}
function kataProvider($dir) {
$src = realpath(__DIR__ . '/../src/' . $dir);
return (new \Haystack\HArray(scandir($src)))
->map(function ($filename) use ($src) {
return sprintf('%s/%s', $src, $filename);
})
->filter(function ($path) {
return false === is_dir($path);
})
->map(function ($filepath) use ($src, $dir) {
$filepath = str_replace('.php', '', $filepath);
return str_replace($src . '/', '\\RethinkingLoops\\' . $dir . '\\', $filepath);
})
// [ "\\RethinkingLoops\\FizzBuzz\\Canonical",
// "\\RethinkingLoops\\FizzBuzz\\Haystack",
// "\\RethinkingLoops\\FizzBuzz\\SomeInterface" ]
}
function kataProvider($dir) {
$src = realpath(__DIR__ . '/../src/' . $dir);
return (new \Haystack\HArray(scandir($src)))
->map(function ($filename) use ($src) {
return sprintf('%s/%s', $src, $filename);
})
->filter(function ($path) {
return false === is_dir($path);
})
->map(function ($filepath) use ($src, $dir) {
$filepath = str_replace('.php', '', $filepath);
return str_replace($src . '/', '\\RethinkingLoops\\' . $dir . '\\', $filepath);
})
->filter(function ($fqcn) {
return false === (new \ReflectionClass($fqcn))->isAbstract();
})
->toArray();
// [ "\\RethinkingLoops\\FizzBuzz\\Canonical",
// "\\RethinkingLoops\\FizzBuzz\\Haystack" ]
}
function kataProvider($dir) {
$src = realpath(__DIR__ . '/../src/' . $dir);
return (new \Haystack\HArray(scandir($src)))
->map(function ($filename) use ($src) {
return sprintf('%s/%s', $src, $filename);
})
->filter(function ($path) {
return false === is_dir($path);
})
->map(function ($filepath) use ($src, $dir) {
$filepath = str_replace('.php', '', $filepath);
return str_replace($src . '/', '\\RethinkingLoops\\' . $dir . '\\', $filepath);
})
->filter(function ($fqcn) {
return false === (new \ReflectionClass($fqcn))->isAbstract();
})
->toArray();
}
use Transducers as t;
$xf = t\comp(
t\drop(2),
t\map(function ($x) { return $x + 1; },
t\filter(function ($x) { return $x % 2; },
t\take(3)
);
$data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
$result = t\xform($data, $xf); // [5, 7, 9]
$elements = [1, 3, 5];
// live
$result = array_map(function($x) { return $x * 2; }, $elements);
// proposed
$result = array_map(function($x) => $x * 2, $elements);
$friends = new \Haystack\HArray(['John', 'Chris', 'Penelope', 'Megan']);
$greetings = $friends
->filter(function ($name) => strlen($name) < 6)
->map(function ($name) => 'Hello ' . $name);
echo join(", ", $greetings->toArray());
// "Hello John, Hello Chris, Hello Megan"
$ composer create-project johnkary/rethinking-loops
(defn encode
[#^InputStream input #^Writer output #^String alphabet line-length]
(let [buffer (make-array Byte/TYPE 3)]
(loop [line 0]
(let [len (.read input buffer)]
(when (pos? len)
(let [b0 (Integer/valueOf (int (aget buffer 0)))
b1 (Integer/valueOf (int (aget buffer 1)))
b2 (Integer/valueOf (int (aget buffer 2)))]
(cond (= len 3)
(let [s0 (bit-and 0x3F (bit-shift-right b0 2))
s1 (bit-and 0x3F
(bit-or (bit-shift-left b0 4)
(bit-shift-right b1 4)))
s2 (bit-and 0x3F
(bit-or (bit-shift-left b1 2)
(bit-shift-right b2 6)))
s3 (bit-and 0x3F b2)]
(.append output (.charAt alphabet s0))
(.append output (.charAt alphabet s1))
(.append output (.charAt alphabet s2))
(.append output (.charAt alphabet s3))))))))))
$list = [2, 4, 6, 8, 10];
for ($i=0; $i < count($start); $i++) {
$current = $start[$i];
$end[] = $current * 2;
}
foreach ($list as $idx => $value) {
echo $value;
unset($list[$idx]);
}
John Kary • @johnkary
Slides: http://johnkary.net/talks
Feedback: https://joind.in/talk/bad7e
Quantity | One | Arrays |
---|---|---|
NULL | null | [] |
0 | null | [] |
1 | new User() | [new User()] |
3 | :( | [ new User(), new User(), new User(), ] |
a lot | :( | [...] |
/** @param User[]|User|null $users */
function findUserGroups($users) {
if ($users === null) return null;
if ($users instanceof User) {
$groups = Group::findByUser($users->id);
return $groups;
}
if (count($users) === 0) {
return [];
} else {
$groups = [];
foreach ($users as $user) {
$userGroups = Group::findByUser($user->id);
if (!$groups) continue;
$groups = array_merge($groups, $userGroups);
}
}
return $groups;
}
/** @param User[]|User|null $users */
function findUserGroups($users) {
$groups = [];
foreach ((array) $users as $user) {
$userGroups = Group::findByUser($user->id);
if (!$groups) continue;
$groups = array_merge($groups, $userGroups);
}
return $groups;
}
/** @param User[]|User|null $users */
function findUserGroups($users) {
$groups = [];
foreach ((array) $users as $user) {
$groups = array_merge($groups, (array) Group::findByUser($user->id));
}
return $groups;
}
function findUserGroups($users) {
return array_reduce((array) $users, function ($groups, $user) {
return array_merge($groups, (array) Group::findByUser($user->id));
}, []);
}