Skip to content

Instantly share code, notes, and snippets.

@rmhdev
Created March 23, 2011 20:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rmhdev/883875 to your computer and use it in GitHub Desktop.
Save rmhdev/883875 to your computer and use it in GitHub Desktop.
My solution to the Array Siblings problem.
<?php
interface ArraySiblingsInterface {
public static function previous($needle, $haystack, $continueAtTop = true);
public static function next($needle, $haystack, $continueAtBottom = true);
}
class ArraySiblings implements ArraySiblingsInterface {
const FORWARD = 'fwd';
const BACKWARDS = 'bwd';
public static function previous($needle, $haystack, $continueAtTop = true) {
return self::get($needle, $haystack, self::BACKWARDS, $continueAtTop);
}
public static function next($needle, $haystack, $continueAtBottom = true) {
return self::get($needle, $haystack, self::FORWARD, $continueAtBottom);
}
private static function get($needle, $haystack, $direction = self::FORWARD, $continueAtBounds = true) {
if (!isset($haystack[$needle])) {
return null;
}
if (sizeof($haystack) == 1) {
return $continueAtBounds ? $haystack[$needle] : null;
}
if ($direction == self::FORWARD) {
return self::getNext($needle, $haystack, $continueAtBounds);
} else {
return self::getPrevious($needle, $haystack, $continueAtBounds);
}
}
private static function getNext($needle, $haystack, $continueAtBounds) {
$keys = array_keys($haystack);
$nextPosition = self::getNextPosition($needle, $keys, $continueAtBounds);
$values = array_values($haystack);
return $values[$nextPosition];
}
private static function getPrevious($needle, $haystack, $continueAtBounds) {
$keys = array_keys($haystack);
$prevPosition = self::getPreviousPosition($needle, $keys, $continueAtBounds);
$values = array_values($haystack);
return $values[$prevPosition];
}
private static function getNextPosition($needle, $keys, $continueAtBounds) {
return self::getPreviousOrNextPosition($needle, $keys, $continueAtBounds, self::FORWARD);
}
private static function getPreviousPosition($needle, $keys, $continueAtBounds) {
return self::getPreviousOrNextPosition($needle, $keys, $continueAtBounds, self::BACKWARDS);
}
private static function getPreviousOrNextPosition($needle, $keys, $continueAtBounds, $direction) {
$sizeof = sizeof($keys);
$actualPosition = array_search($needle, $keys);
$isAtBounds = self::isAtBounds($actualPosition, $sizeof, $direction);
if ((!$continueAtBounds) && ($isAtBounds)) {
return null;
}
return self::calculatePreviousOrNextPosition($actualPosition, $sizeof, $direction);
}
private static function isAtBounds($actualPosition, $sizeof, $direction) {
return ($direction == self::FORWARD) ?
($actualPosition == ($sizeof - 1)) : ($actualPosition == 0);
}
private static function calculatePreviousOrNextPosition($actualPosition, $sizeof, $direction) {
return ($direction == self::FORWARD) ?
(($actualPosition + 1) % $sizeof) : abs((($actualPosition + 1) - $sizeof));
}
}
class ArraySiblingsTest extends PHPUnit_Framework_TestCase {
protected $coll = array(
'lalala' => 1,
'pepepe' => 2,
'cocotero' => 3,
'periquito' => 4
);
public function testShouldReturnNullIfTheNeedleDoesNotExistInHaystack() {
$this->assertEquals(null, ArraySiblings::next('chuchu', $this->coll));
}
public function testShouldTheNeedleElementIfOnlyOneElementInHaystack() {
$this->assertEquals('blabla', ArraySiblings::next('chuchu', array('chuchu' => 'blabla')));
}
public function testShouldReturnNextSibling() {
$this->assertEquals(3, ArraySiblings::next('pepepe', $this->coll));
}
public function testShouldReturnPreviousSibling() {
$this->assertEquals(2, ArraySiblings::previous('cocotero', $this->coll));
}
public function testShouldGoBeyondBoundsAtTop() {
$this->assertEquals(1, ArraySiblings::next('periquito', $this->coll));
}
public function testShouldGoBeyondBoundsAtBottom() {
$this->assertEquals(4, ArraySiblings::previous('lalala', $this->coll));
}
public function testShouldReturnNullIfOnlyOneElementInArrayAndToldNotToContinueAtBounds() {
$this->assertEquals(null, ArraySiblings::next('chuchu', array('chuchu' => 'blabla'), false));
$this->assertEquals(null, ArraySiblings::previous('chuchu', array('chuchu' => 'blabla'), false));
}
public function testShouldReturnNullIfToldNotToContinueAtTop() {
$this->assertEquals(null, ArraySiblings::next('periquito', $this->coll, false));
}
public function testShouldReturnNullIfToldNotToContinueAtBottom() {
$this->assertEquals(null, ArraySiblings::previous('lalala', $this->coll, false));
}
}
@ggalmazor
Copy link

Súper interesante cómo usar el operador % para dar la vuelta al final del array con:

$pos_siguiente = (($pos_actual + 1) % $sizeof);

Me la apunto!

@rmhdev
Copy link
Author

rmhdev commented Mar 23, 2011

He refactorizado el código, que había un poco de "code smell" ;) A ver si la gente se anima y aporta soluciones!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment