Skip to content
This repository has been archived by the owner on Jan 11, 2023. It is now read-only.

Commit

Permalink
Merge pull request #19 from robations/feature/chunk-without-group
Browse files Browse the repository at this point in the history
Implement chunking without use of group iterator
  • Loading branch information
davidroth committed Nov 4, 2015
2 parents 7c5a10c + de4f192 commit 896ea6c
Show file tree
Hide file tree
Showing 7 changed files with 250 additions and 27 deletions.
2 changes: 0 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
language: php
php:
- 5.3
- 5.4
- 5.5
- 5.6
install: composer install
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ LINQ queries offer three main advantages over traditional foreach loops:

## Requirements

fusonic/linq is supported on PHP 5.3 and up.
fusonic/linq is supported on PHP 5.5 and up.


## Installation & Usage
Expand Down Expand Up @@ -202,6 +202,6 @@ Linq::from(array(1, 2, "Not a numeric value"))
You can run the test suite with the following command:

```bash
phpunit --bootstrap tests/bootstrap.php .
vendor/bin/phpunit --bootstrap tests/bootstrap.php .
```

5 changes: 4 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
}
],
"require": {
"php": ">=5.3.2"
"php": ">=5.5.0"
},
"autoload": {
"psr-0": {
"Fusonic\\Linq": "src/"
}
},
"require-dev": {
"phpunit/phpunit": "^4.0"
}
}
96 changes: 96 additions & 0 deletions src/Fusonic/Linq/Iterator/ChunkIterator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

/*
* This file is part of Fusonic-linq.
* https://github.com/fusonic/fusonic-linq
*
* (c) Fusonic GmbH
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Fusonic\Linq\Iterator;

use Fusonic\Linq\Linq;
use Iterator;

/**
* Iterates over an iterator, returning Linq objects of the given chunk size.
*/
class ChunkIterator implements Iterator
{
/**
* @var Iterator
*/
private $iterator;

/**
* @var array
*/
private $chunk;

/**
* @var int
*/
private $i = 0;

/**
* @var int
*/
private $chunkSize;

public function __construct(Iterator $iterator, $chunkSize)
{
$this->iterator = $iterator;
$this->chunkSize = $chunkSize;
}

/**
* @return Linq
*/
public function current()
{
return new Linq($this->chunk);
}

public function next()
{
$this->iterator->next();
$this->chunk = $this->getNextChunk();
$this->i++;
}

private function getNextChunk()
{
$chunk = [];
while ($this->iterator->valid()) {
$chunk[] = $this->iterator->current();

if (count($chunk) < $this->chunkSize) {
$this->iterator->next();
} else {
break;
}
}

return $chunk;
}

public function key()
{
return $this->i;
}

public function valid()
{
return !empty($this->chunk);
}

public function rewind()
{
$this->iterator->rewind();
$this->i = 0;
$this->chunk = $this->getNextChunk();
}
}
25 changes: 3 additions & 22 deletions src/Fusonic/Linq/Linq.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Fusonic\Linq;

use Countable;
use Fusonic\Linq\Iterator\ChunkIterator;
use Fusonic\Linq\Iterator\ExceptIterator;
use Fusonic\Linq\Iterator\DistinctIterator;
use Fusonic\Linq\Iterator\GroupIterator;
Expand Down Expand Up @@ -176,7 +177,7 @@ public function aggregate($func, $seed = null)
/**
* Splits the sequence in chunks according to $chunksize.
*
* @param $chunksize Specifies how many elements are grouped together per chunk.
* @param int $chunksize Specifies how many elements are grouped together per chunk.
* @throws \InvalidArgumentException
* @return Linq
*/
Expand All @@ -186,27 +187,7 @@ public function chunk($chunksize)
throw new \InvalidArgumentException("chunksize", $chunksize);
}

$i = -1;
return $this->select(
function ($x) use (&$i) {
$i++;
return array("index" => $i, "value" => $x);
}
)
->groupBy(
function ($pair) use ($chunksize) {
return $pair["index"] / $chunksize;
}
)
->select(
function (GroupedLinq $group) {
return $group->select(
function ($v) {
return $v["value"];
}
);
}
);
return Linq::from(new ChunkIterator($this->iterator, $chunksize));
}

/**
Expand Down
123 changes: 123 additions & 0 deletions tests/Fusonic/Linq/Test/ChunkIteratorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?php

namespace Fusonic\Linq\Test;

use Fusonic\Linq\Iterator\ChunkIterator;
use Fusonic\Linq\Linq;

class ChunkIteratorTest extends \PHPUnit_Framework_TestCase
{
public function testEmptyIterator()
{
$x = new ChunkIterator(new \ArrayIterator([]), 1);

$x->rewind();
$this->assertEquals(false, $x->valid());
}

public function testChunkSizeLargerThanIterator()
{
$x = new ChunkIterator(new \ArrayIterator([0, 1]), 100);

$x->rewind();
$this->assertEquals(true, $x->valid());
$this->assertEquals([0, 1], $x->current()->toArray());
}

public function testChunkSizeSmallerThanIterator()
{
$x = new ChunkIterator(new \ArrayIterator([0, 1, 2]), 2);

$x->rewind();
$this->assertEquals(true, $x->valid());
$this->assertEquals([0, 1], $x->current()->toArray());

$x->next();
$this->assertEquals(true, $x->valid());
$this->assertEquals([2], $x->current()->toArray());

$x->next();
$this->assertEquals(false, $x->valid());
}

public function testCharElementsScenario()
{
$x = new ChunkIterator(new \ArrayIterator(["a", "b", "c", "d", "e"]), 2);

$x->rewind();
$this->assertEquals(true, $x->valid());
$this->assertEquals(["a", "b"], $x->current()->toArray());

$x->next();
$this->assertEquals(true, $x->valid());
$this->assertEquals(["c", "d"], $x->current()->toArray());

$x->next();
$this->assertEquals(true, $x->valid());
$this->assertEquals(["e"], $x->current()->toArray());

$x->next();
$this->assertEquals(false, $x->valid());
}

public function testDifferentChunkSize()
{
$x = new ChunkIterator(new \ArrayIterator([0, 1, 2, 3, 4, 5, 6, 7, 8]), 3);

$arr = array_map(
function (Linq $y) {
return implode(",", $y->toArray());
},
iterator_to_array($x)
);
$this->assertEquals(
["0,1,2", "3,4,5", "6,7,8"],
$arr
);
}

public function testIdempotency()
{
$x = new ChunkIterator(new \ArrayIterator([0, 1, 2]), 2);

$x->rewind();
$this->assertEquals(true, $x->valid());
$this->assertEquals([0, 1], $x->current()->toArray());
$this->assertEquals([0, 1], $x->current()->toArray());
$x->next();

$this->assertEquals([2], $x->current()->toArray());
$this->assertEquals([2], $x->current()->toArray());
}

public function testNext()
{
$x = new ChunkIterator(new \ArrayIterator([0, 1, 2]), 2);

$x->rewind();
$x->next();
$this->assertEquals([2], $x->current()->toArray());
}

public function testKey()
{
$x = new ChunkIterator(new \ArrayIterator([0, 1, 2]), 2);

$x->rewind();
$this->assertEquals(0, $x->key());
$x->next();
$this->assertEquals(1, $x->key());
}

public function testRewind()
{
$x = new ChunkIterator(new \ArrayIterator([0, 1, 2]), 2);

$x->rewind();
$x->next();
$x->rewind();
$this->assertEquals(true, $x->valid());
$this->assertEquals(0, $x->key());
$this->assertEquals([0, 1], $x->current()->toArray());
}
}
22 changes: 22 additions & 0 deletions tests/Fusonic/Linq/Test/LinqTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1698,6 +1698,28 @@ public function testIssue3_emtpyCollectionOrdering()
->toArray();
}

public function testChunkWithoutGrouping()
{
$log = [];
Linq::from([0, 1, 2, 3])
->where(function($x) use(&$log) {
$log[] = 'where';
return true;
})
->select(function($x) use(&$log) {
$log[] = 'select';
return $x;
})
->chunk(2)
->each(function(Linq $chunk) use(&$log) {
$log[] = 'each';
return $chunk;
})
;

$this->assertEquals('where select where select each where select where select each', implode(' ', $log));
}

/**
* @test
*/
Expand Down

0 comments on commit 896ea6c

Please sign in to comment.