2015-01-06 3 views
2

저는 모든 회원에게 5 년간 주소 기록을 제공하기 위해 현지 법 집행 기관에서 요구하는 온라인 회원 시스템을 보유하고 있습니다. 이 5 년 안에 겹치는 것이 허용되지만 틈이 없을 수도 있습니다. 회원은 자신의 주소를 입력하고 주소가 mysql 데이터베이스에 저장되고 각 주소는 & 사이에 저장됩니다. 데이터는 회원이 월 단위로 입력합니다. 이것은 '시작'날짜의 월 첫 번째이자 '종료'날짜의 마지막 월으로 저장됩니다.php - 더 넓은 범위의 틈새에 대해 여러 날짜 범위 확인

특정 회원이 제공 한 주소의 모든 날짜 범위를 가져올 수 있도록 데이터베이스의 mysqli 쿼리에서 컴파일 된 $ array가 있습니다. 이 배열은 내 루프를 멋지게 채 웁니다.

$array[] = array("from"=>$row['date_from'],"to"=>$row['date_to']); 

주소 역사에 차이가있는 경우에도 그것은 5 년 이상 수 있습니다 내가 일 길이의 숫자로이 범위의 각을 변환하고 모든 추가 시도했지만 주소 (필요한 & 허용) 겹쳐진 .

내가 필요한 것은 $ complete가 TRUE 또는 FALSE가 될 때까지 필요한 간격이 필요 없다는 것입니다.

mysql 쿼리 또는 php로 열기.

반 작업 코드를 제공하지 않아 죄송합니다. 내 생각은 각각의 코드가 표시되는지 확인하기 위해 1825 일 (5 년) 동안 반복하는 것입니다.

+0

SQL 솔루션을 원할 경우 데이터가 제공되는 테이블 구조에 대한 추가 정보를 제공해야합니다. 샘플 데이터는 항상 도움이됩니다. –

+0

@ GordonLinoff 나는 그것이 도움이되었을 것 인 방법을 볼 수있다. .. 미안 2am이었다! – SLV

답변

2

이 재귀 함수는 가능한 한 많이 결합 될 때까지 겹치는 범위를 결합하여 범위 배열을 통과합니다. 결과가 둘 이상의 범위 인 경우 간격이 있습니다. 나는 또한 도우미 함수를 사용하여 겹쳐진 부분을 더 깔끔하고 쉽게 찾을 수있게했으며, 귀하의 날짜가 'Y-m-d' 인 것으로 가정합니다.

<?php 

// First, here's how to use it. If we can't combine all the ranges, and the 
// final combined range doesn't reach back 5 years or to the present, 
// we have a gap. 
$mergedRanges = combineRanges($myArray); 
if (count($mergedRanges) > 1 
    || $mergedRanges[0]['from'] > date('Y-m-d', time() - 157680000) // 5 years ago 
    || $mergedRanges[0]['to'] < date('Y-m-d')) // present 
    echo 'Gaps found'; 

/** 
* Recursive function to combine ranges. 
* 
* @param array $ranges 
* @return array Array of combined ranges (has only 1 element if no gaps) 
*/ 
function combineRanges(array $ranges) 
{ 
    $mergedRanges = array(); 
    $usedKeys = array(); 

    // Nested foreach compares each unique pair of ranges for overlap. 
    // If the a range has already been accounted for, it can be skipped. 
    foreach ($ranges as $k1 => $range1) { 
     if (!in_array($k1, $usedKeys)) { 
      foreach ($ranges as $k2 => $range2) { 
       if (!in_array($k1, $usedKeys) && $k1 > $k2) { 

        // If ranges overlap, combine them and make a note that 
        // they've already been included 
        if (rangesOverlap($range1, $range2)) { 
         $newRange = array(
          'from' => min($range1['from'], $range2['from']), 
          'to' => max($range1['to'], $range2['to']) 
         ); 
         // It's possible the resulting range could already 
         // be accounted for by a different combo of ranges, 
         // so check first 
         if (!in_array($newRange, $mergedRanges)) 
          $mergedRanges[] = $newRange; 
         $usedKeys[] = $k1; 
         $usedKeys[] = $k2; 

        // Otherwise, add the 2nd range to $mergedRanges 
        } elseif (!in_array($k2, $usedKeys)) { 
         $mergedRanges[] = $range2; 
         $usedKeys[] = $k2; 
        } 

        // If $range1 didn't have any overlaps, add it here 
        if (!in_array($k1, $usedKeys)) { 
         $mergedRanges[] = $range1; 
         $usedKeys[] = $k1; 
        } 
       } 
      } 
     } 
    } 

    // If $ranges and $mergedRanges have the same # of elements, 
    // or if $ranges only had 1 element to begin with, 
    // that means we couldn't merge any more. Otherwise, recurse! 
    if (count($ranges) == 1) 
     return $ranges; 
    return count($mergedRanges) == 1 || (count($ranges) == count($mergedRanges)) 
     ? $mergedRanges 
     : combineRanges($mergedRanges); 
} 

/** 
* Helper function to see if 2 ranges overlap. 
* 
* @param array $range1 
* @param array $range2 
* @return boolean 
*/ 
function rangesOverlap(array $range1, array $range2) 
{ 
    // Find the day before each range in order to combine ranges 
    // that don't overlap but are right next to each other. 
    $overlap = false; 
    $range1Before = date('Y-m-d', strtotime('-1 day', strtotime($range1['from']))); 
    $range2Before = date('Y-m-d', strtotime('-1 day', strtotime($range2['from']))); 

    // Account for when $range1 is first or when $range 2 is first 
    if ($range1['from'] <= $range2['from'] && $range1['to'] >= $range2Before 
     || $range2['from'] <= $range1['from'] && $range2['to'] >= $range1Before) 
     $overlap = true; 

    return $overlap; 
} 
+0

성공적으로 구현하기가 어렵다는 것을 알게되면, require_once로 호출하는 별도의 페이지에 함수가 있고, 메인 페이지에서 호출 한 후 첫 번째 부분이 있습니다. 테스트를 위해서 배열은 현재'Array \t ( [0] => 배열 ([from] => 2008-06-30 [to] => 2015-01-06) \t)' – SLV

+0

죄송합니다. 첫 번째 입력에 요소가 하나 뿐인 경우 함수에서 테스트 케이스와 같은 것을 고려하지 않았습니다. 'combineRanges()'의 마지막 return 바로 위에 추가 한'return' 조건을 보시기 바랍니다. – mopo922

+0

@SLV에 행운이 있습니까? – mopo922