diff --git a/src/Illuminate/Support/LazyCollection.php b/src/Illuminate/Support/LazyCollection.php index 67318f40e16b..c0d6c2bd54ce 100644 --- a/src/Illuminate/Support/LazyCollection.php +++ b/src/Illuminate/Support/LazyCollection.php @@ -109,6 +109,42 @@ public function eager() return new static($this->all()); } + /** + * Cache values as they're enumerated. + * + * @return static + */ + public function remember() + { + $iterator = $this->getIterator(); + + $iteratorIndex = 0; + + $cache = []; + + return new static(function () use ($iterator, &$iteratorIndex, &$cache) { + for ($index = 0; true; $index++) { + if (array_key_exists($index, $cache)) { + yield $cache[$index][0] => $cache[$index][1]; + + continue; + } + + if ($iteratorIndex < $index) { + $iterator->next(); + + $iteratorIndex++; + } + + if (! $iterator->valid()) break; + + $cache[$index] = [$iterator->key(), $iterator->current()]; + + yield $cache[$index][0] => $cache[$index][1]; + } + }); + } + /** * Get the average value of a given key. * diff --git a/tests/Support/SupportLazyCollectionIsLazyTest.php b/tests/Support/SupportLazyCollectionIsLazyTest.php index fcf61e4b772d..ac43df18c20c 100644 --- a/tests/Support/SupportLazyCollectionIsLazyTest.php +++ b/tests/Support/SupportLazyCollectionIsLazyTest.php @@ -763,6 +763,27 @@ public function testRejectIsLazy() }); } + public function testRememberIsLazy() + { + $this->assertDoesNotEnumerate(function ($collection) { + $collection->remember(); + }); + + $this->assertEnumeratesOnce(function ($collection) { + $collection = $collection->remember(); + + $collection->all(); + $collection->all(); + }); + + $this->assertEnumerates(5, function ($collection) { + $collection = $collection->remember(); + + $collection->take(5)->all(); + $collection->take(5)->all(); + }); + } + public function testReplaceIsLazy() { $this->assertDoesNotEnumerate(function ($collection) { diff --git a/tests/Support/SupportLazyCollectionTest.php b/tests/Support/SupportLazyCollectionTest.php index cb3582b9cc02..48b01719a3c0 100644 --- a/tests/Support/SupportLazyCollectionTest.php +++ b/tests/Support/SupportLazyCollectionTest.php @@ -80,6 +80,66 @@ public function testEager() $this->assertSame([1, 2, 3, 4, 5], $data->all()); } + public function testRemember() + { + $source = [1, 2, 3, 4]; + + $collection = LazyCollection::make(function () use (&$source) { + yield from $source; + })->remember(); + + $this->assertSame([1, 2, 3, 4], $collection->all()); + + $source = []; + + $this->assertSame([1, 2, 3, 4], $collection->all()); + } + + public function testRememberWithTwoRunners() + { + $source = [1, 2, 3, 4]; + + $collection = LazyCollection::make(function () use (&$source) { + yield from $source; + })->remember(); + + $a = $collection->getIterator(); + $b = $collection->getIterator(); + + $this->assertEquals(1, $a->current()); + $this->assertEquals(1, $b->current()); + + $b->next(); + + $this->assertEquals(1, $a->current()); + $this->assertEquals(2, $b->current()); + + $b->next(); + + $this->assertEquals(1, $a->current()); + $this->assertEquals(3, $b->current()); + + $a->next(); + + $this->assertEquals(2, $a->current()); + $this->assertEquals(3, $b->current()); + + $a->next(); + + $this->assertEquals(3, $a->current()); + $this->assertEquals(3, $b->current()); + + $a->next(); + + $this->assertEquals(4, $a->current()); + $this->assertEquals(3, $b->current()); + + $b->next(); + + $this->assertEquals(4, $a->current()); + $this->assertEquals(4, $b->current()); + } + public function testTapEach() { $data = LazyCollection::times(10);