2010-09-02 9 views
14

ho un array nel seguente formato:Unione di intervalli sovrapposti in array PHP?

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

Dove ogni elemento è una gamma X-a-Y. Quello che vorrei per unire le gamme di sovrapposizione nella matrice, per ottenere qualcosa di più simile a questo:

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), 
); 

Quale sarebbe il modo migliore per ottenere questo risultato?

risposta

18

Non testato, ma l'idea è di ordinare i dati prima dal primo elemento, quindi unire gli elementi successivi con il precedente il più a lungo possibile.

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 Questo è il più pulito e più efficiente essere O (n). Questo è esattamente l'algoritmo che avevo in mente, mi hai battuto su di esso. – Keyo

+0

Che cosa serve il +1 per @ $ data [$ n] [1]? Quando si usano i numeri in virgola mobile questo non funziona nel mio caso. –

+3

@Tom, con numeri interi, si desidera che '[1,2], [3,4]' sia un singolo intervallo di '[1,4]'. In tal caso, leggerà 'if (3> 2 + 1)', quindi avvierà un nuovo intervallo. Con i numeri in virgola mobile, non è davvero utile. Il +1, può essere eliminato o impostato su un delta molto piccolo (+.00001), a seconda di ciò che consideri abbastanza piccolo da essere lo stesso numero. – Matthew

0

OK, ho redatto questo, quindi potrebbe avere stranezze. Testato con i dati visti di seguito e sembrava funzionare bene. Potrebbe non essere il modo migliore per farlo, ma è un modo e funziona. Domande fammi sapere.

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)); 

Uscite:

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) 
    } 
} 

spero che funziona per ya!

EDIT

vedo sono stato picchiato da un ora = \ Oh bene! Sto ancora postando in quanto è un metodo diverso, ma probabilmente sceglierei il metodo di 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

Questo metodo dovrebbe funzionare, ma rallenterà fino alla ricerca per indicizzazione con intervalli ampi. – Matthew

+0

La migliore risposta, funziona perfettamente. –

Problemi correlati