Functional\unzip make to work on infinite lists
authorwidmogrod <widmogrod@gmail.com>
Thu, 21 Dec 2017 17:53:38 +0000 (18:53 +0100)
committerwidmogrod <widmogrod@gmail.com>
Thu, 21 Dec 2017 17:53:38 +0000 (18:53 +0100)
src/Functional/zipping.php
test/Functional/UnzipTest.php

index 4c70528..cf21fb6 100644 (file)
@@ -50,18 +50,23 @@ const unzip = 'Widmogrod\Functional\unzip';
  *
  * unzip transforms a list of pairs into a list of first components and a list of second components.
  *
- * @param Listt $a
+ * @param Listt $xs
  * @return array
  */
-function unzip(Listt $a): array
+function unzip(Listt $xs): array
 {
-    return foldr(function ($ab, $abs) {
-        [$a, $b] = $ab;
-        [$as, $bs] = $abs;
+    try {
+        [$x, $y] = head($xs);
 
         return [
-            prepend($a, $as),
-            prepend($b, $bs)
+            ListtCons::of(function () use ($x, $xs) {
+                return [$x, unzip(tail($xs))[0]];
+            }),
+            ListtCons::of(function () use ($y, $xs) {
+                return [$y, unzip(tail($xs))[1]];
+            }),
         ];
-    }, [fromNil(), fromNil()], $a);
+    } catch (EmptyListError $e) {
+        return [fromNil(), fromNil()];
+    }
 }
index 0d3b47e..9aaac58 100644 (file)
@@ -2,13 +2,22 @@
 
 namespace test\Functional;
 
-use function Widmogrod\Functional\fromNil;
+use Eris\Generator;
+use Eris\TestTrait;
 use Widmogrod\Primitive\Listt;
+use function Widmogrod\Functional\eql;
+use function Widmogrod\Functional\filter;
 use function Widmogrod\Functional\fromIterable;
+use function Widmogrod\Functional\fromNil;
+use function Widmogrod\Functional\length;
+use function Widmogrod\Functional\repeat;
+use function Widmogrod\Functional\take;
 use function Widmogrod\Functional\unzip;
 
 class UnzipTest extends \PHPUnit_Framework_TestCase
 {
+    use TestTrait;
+
     /**
      * @dataProvider provideData
      */
@@ -41,4 +50,18 @@ class UnzipTest extends \PHPUnit_Framework_TestCase
             ],
         ];
     }
+
+    public function test_it_should_work_on_infinite_lists()
+    {
+        $this->forAll(
+            Generator\choose(1, 100),
+            Generator\string(),
+            Generator\string()
+        )->then(function ($n, $x, $y) {
+            [$xs, $ys] = unzip(repeat([$x, $y]));
+
+            return length(filter(eql($x), take($n, $xs))) === $n
+                && length(filter(eql($y), take($n, $ys))) === $n;
+        });
+    }
 }