2010-09-02 6 views
14

Ich habe ein Array in dem folgenden Format:Verschachtelte Bereiche in PHP-Arrays zusammenführen?

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

dem jedes Element einen Bereich X zu Y ist. Was würde Ich mag die überlappende Bereiche in der Matrix verschmelzen, etwas mehr wie folgt zu erhalten:

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

Was wäre der beste Weg, um dies zu erreichen

?

Antwort

18

Nicht getestet, aber die Idee hier ist, die Daten zuerst nach dem ersten Element zu sortieren, dann die nachfolgenden Elemente so lange wie möglich mit dem vorherigen zusammenzuführen.

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 Dies ist die sauberste und effizient ist O (n). Das ist genau der Algorithmus, den ich im Sinn hatte, du hast mich dazu geschlagen. – Keyo

+0

Was bedeutet +1 für @ $ Daten [$ n] [1]? Bei der Verwendung von Fließkommazahlen funktioniert das in meinem Fall nicht. –

+3

@Tom, mit ganzen Zahlen wollen Sie '[1,2], [3,4]' zu einem einzigen Bereich von '[1,4]'. In diesem Fall würde es 'if (3> 2 + 1)' lesen und dann einen neuen Bereich beginnen. Mit Gleitkommazahlen ist es nicht wirklich nützlich. Die +1 können gelöscht oder auf ein sehr kleines Delta (+.00001) gesetzt werden, je nachdem, was Sie für klein genug halten, um dieselbe Nummer zu erhalten. – Matthew

0

In Ordnung, entworfen dies, so dass es Macken haben kann. Getestet mit den unten gezeigten Daten und schien gut zu funktionieren. Ist vielleicht nicht der beste Weg, es zu tun, aber es ist ein Weg und es funktioniert. Fragen lassen Sie mich wissen.

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

Ausgänge:

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

Hoffe, dass es für ya funktioniert!

EDIT

Ich sehe, ich wurde von einer Stunde geschlagen out = \ Oh gut! Ich poste immer noch, da es eine andere Methode ist, ich würde wahrscheinlich stattdessen die Methode von Konforce wählen.

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

Diese Methode sollte funktionieren, aber es wird zu einem Crawl mit großen Bereichen verlangsamen. – Matthew

+0

Beste Antwort, funktioniert perfekt. –