<?php error_reporting(-1); // reader // reads n per call starting from last position til EOF $offset = 0; $reader = function ($n = 100) use (&$offset) { $limit = $offset + $n; $ln = 0; $content = array(); $fp = fopen(__DIR__ . '/txt/data.txt', 'r'); while (($line = fgets($fp)) && $ln < $limit) { $ln++; if($ln < $offset) { continue; } $content[$ln] = (int) trim($line); } fclose($fp); $offset+=$n; return $content; }; // transformer // calculates mediane from set block $median = function ($block) { sort($block); $m = (int) floor(count($block) / 2); return $m % 2 ? $block[$m] : ($block[$m] + $block[$m-1]) / 2; }; // transformer // calculates average value from set block $average = function($block) { return array_sum($block) / count($block); }; // combiner // adds transformer result to array $combiner = function(array $data, $block) { $data[] = $block; return $data; }; // reductor // uses reader, transformer and combiner to reduce input data function reductor($reader, $transformer, $combiner) { if (!is_callable($reader)) { throw new \InvalidArgumentException('Reader must be callable'); } if (!is_callable($transformer)) { throw new \InvalidArgumentException('Transformer must be callable'); } if (!is_callable($combiner)) { throw new \InvalidArgumentException('Combiner must be callable'); } $data = array(); while ($block = $reader()) { $block = $transformer($block); $data = $combiner($data, $block); } return $data; } var_dump(reductor($reader, $median, $combiner));