合并PHP数组中的重叠范围?

Posted

技术标签:

【中文标题】合并PHP数组中的重叠范围?【英文标题】:Merging overlapping ranges in PHP arrays? 【发布时间】:2011-04-07 12:39:18 【问题描述】:

我有一个格式如下的数组:

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

其中每个项目都是 X 到 Y 的范围。我想合并数组中的重叠范围,以获得更像这样的东西:

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

最好的方法是什么?

【问题讨论】:

【参考方案1】:

未经测试,但这里的想法是先按第一个元素对数据进行排序,然后尽可能将后续元素与前一个元素合并。

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 这是最干净和最有效的 O(n)。这正是我想到的算法,你打败了我。 +1 对 @ $data[$n][1] 有什么作用?当使用浮点数时,这在我的情况下不起作用。 @Tom,对于整数,您希望[1,2],[3,4][1,4] 的一个范围。在这种情况下,它将读取if (3 &gt; 2 + 1),然后开始一个新范围。对于浮点数,它并不是很有用。 +1 可以丢弃或设置为非常小的增量 (+.00001),具体取决于您认为足够小的相同数字。 这个 O(n) 怎么样?开头的排序已经是nlogn了。 你是个邪恶的天才!!尽管我在日期上执行此操作,但您为我节省了一些 CPU 和几行代码(只需要在除第二个 if() 块之外的所有地方使用 strtotime()(显然!)并添加 60(即 60 秒)而不是 @ 987654328@ 在第一个 if() 块中).. 很想看看(作为更新)是否有更好的方法来合并日期时间范围(虽然还不够绝望,无法发布新问题)。【参考方案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);

【讨论】:

这个方法应该可以,但它会减慢到大范围的爬行。【参考方案3】:

好的,这是草拟的,所以它可能有怪癖。用下面看到的数据对其进行了测试,似乎工作得很好。可能不是最好的方法,但它是一种方法,它确实有效。有问题请告诉我。

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

输出:

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)
  

希望它对你有用!

编辑

我知道我被打败了一个小时=\哦,好吧!我仍在发帖,因为它是一种不同的方法,当然我可能会选择 konforce 的方法。

【讨论】:

以上是关于合并PHP数组中的重叠范围?的主要内容,如果未能解决你的问题,请参考以下文章

php 合并多个数组中的数字

php 数组相同的元素组合并在一起

在 PHP 中的 while() 中合并数组

比较两个爆炸的 php 数组以查找重叠的问题

论php数组合并

php下将多个数组合并成一个数组的方法与实例代码