public
Last active — forked from ggalmazor/ArraySiblingsTest.php

My solution to the Array Siblings problem.

  • Download Gist
ArraySiblingsTest.php
PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
<?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));
}
 
}

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!

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

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.