2010-09-02 14 views
14

I tienen una matriz en el siguiente formato:¿Combinación de rangos superpuestos en matrices PHP?

array(
    0 => array(1, 5), 
    1 => array(4, 8), 
    2 => array(19, 24), 
    3 => array(6, 9), 
    4 => array(11, 17), 
); 

Cuando cada artículo es una gama X-a-Y. Lo que me gustaría fusionar los intervalos que se solapan en la matriz, para conseguir algo de la misma familia:

array(
    0 => array(1, 9), // 1-5, 4-8 and 6-9 are overlapping, so they are merged 
    1 => array(11, 17), 
    2 => array(19, 24), 
); 

lo que sería la mejor manera de lograr esto?

Respuesta

18

No probado, pero la idea aquí es ordenar los datos primero por el primer elemento, luego combinar los elementos subsiguientes con el anterior el mayor tiempo posible.

usort($data, function($a, $b) 
{ 
     return $a[0] - $b[0]; 
}); 

$n = 0; $len = count($data); 
for ($i = 1; $i < $len; ++$i) 
{ 
     if ($data[$i][0] > $data[$n][1] + 1) 
       $n = $i; 
     else 
     { 
       if ($data[$n][1] < $data[$i][1]) 
         $data[$n][1] = $data[$i][1]; 
       unset($data[$i]); 
     } 
} 

$data = array_values($data); 
+1

+1 Este es el más limpio y más eficiente ser O (n). Este es exactamente el algoritmo que tenía en mente, tú me ganaste. – Keyo

+0

¿Qué sirve el +1 para @ $ data [$ n] [1]? Cuando uso números de coma flotante esto no funciona en mi caso. –

+3

@Tom, con números enteros, quiere '[1,2], [3,4]' para ser un único rango de '[1,4]'. En ese caso, leería 'if (3> 2 + 1)' y luego comenzaría un nuevo rango. Con números de coma flotante, no es realmente útil. El +1, puede soltarse o establecerse en un delta muy pequeño (+.00001), dependiendo de lo que considere lo suficientemente pequeño como para ser el mismo número. – Matthew

0

De acuerdo, redactó esto, por lo que puede tener peculiaridades. Lo probé con los datos que se muestran a continuación y pareció funcionar bien. Puede que no sea la mejor manera de hacerlo, pero es de una manera y funciona. Preguntas házmelo saber.

function combineRange($array) { 
    if (is_array($array)) { 
     // Sort the array for numerical order 
     sort($array); 

     // Set Defaults 
     $prev = array(); 
     $prev_key = null; 

     foreach ($array as $key => $item) { 
      // First time around setup default data 
      if (empty($prev)) { 
       $prev = $item; 
       $prev_key = $key; 
       continue; 
      } 

      if ($item[0] >= $prev[0] && $item[0] <= $prev[1]) { 
       // Incase the last number was less than do not update 
       if ($array[$prev_key][1] < $item[1]) 
        $array[$prev_key][1] = $item[1]; 

       unset($array[$key]); 
      }else { 
       $prev_key = $key; 
      }  

      $prev = $item; 
     } 
    } 

    return $array; 
} 

$array = array(
    5 => array(13, 16), 
    0 => array(1, 5), 
    1 => array(4, 8), 
    2 => array(19, 24), 
    3 => array(6, 9), 
    4 => array(11, 17), 
    6 => array(21, 30), 
); 

var_dump(combineRange($array)); 

Salidas:

array(3) { 
    [0]=> 
    array(2) { 
    [0]=> 
    int(1) 
    [1]=> 
    int(9) 
    } 
    [3]=> 
    array(2) { 
    [0]=> 
    int(11) 
    [1]=> 
    int(17) 
    } 
    [5]=> 
    array(2) { 
    [0]=> 
    int(19) 
    [1]=> 
    int(30) 
    } 
} 

espero que funcione para ti!

EDITAR

veo fui golpeado por una hora = \ Oh, bueno! Todavía estoy publicando, ya que es un método diferente, concede que, en su lugar, probablemente elegiría el método de konforce.

2
$input = array(0 => array(1, 5), 
       1 => array(4, 8), 
       2 => array(19, 24), 
       3 => array(6, 9), 
       4 => array(11, 17), 
      ); 


$tmpArray = array(); 
foreach($input as $rangeSet) { 
    $tmpArray = array_unique(array_merge($tmpArray,range($rangeSet[0],$rangeSet[1]))); 
} 


sort($tmpArray); 

$oldElement = array_shift($tmpArray); 
$newArray = array(array($oldElement)); 
$ni = 0; 
foreach($tmpArray as $newElement) { 
    if ($newElement > $oldElement+1) { 
     $newArray[$ni++][] = $oldElement; 
     $newArray[$ni][] = $newElement; 
    } 
    $oldElement = $newElement; 
} 
$newArray[$ni++][] = $oldElement; 

var_dump($newArray); 
+0

Este método debería funcionar, pero se ralentizará hasta convertirse en un rastreo con grandes rangos. – Matthew

+0

La mejor respuesta, funciona perfecto. –

Cuestiones relacionadas