在使用数组的复杂计算中避免循环

时间:2014-12-17 11:16:59

标签: php arrays loops

我有两个数字数组,一个包含很多数字,一个只包含少数数字。数组内或数组之间没有重复:

$all = range(1, 50);
$few = array(7, 11, 19, 27, 29, 36, 40, 43);
$many = array_merge(array_diff($all, $few));

我现在想要计算每个“少数”数字之间的差异以及跟随它的所有“许多”之间的差异,但是在“少数”的下一个之前。例如,在$many中,只有28来自$few,介于27和29之间,所以我想计算28到27之间的差异。没有计算27的其他差异,因为没有其他{{1}从$many开始19,我将计算差异为20,21,22,23,24,25和26,因为它们都位于19和{{1的下一个数字之间,这是27。

为了计算差异,我使用循环。这是一个稍微简化的代码(忽略了$few中最后一个数字没有索引$few这一事实:

[$i + 1]

如果我有庞大的数组,循环将需要很长时间才能运行。所以:

有没有更好的方法来计算差异,而不使用循环?


结果$few如下所示:

$differences = array();
for($i = 0; $i < count($few); $i++) {
    foreach($many as $m) {
        if($m > $few[$i] && $m < $few[$i + 1]) {
            $differences[] = $m - $few[$i];
        }
    }
}

我的基本推理是,作为一个人,我没有看到我比较的两个数组:

$differences

而是一个number line,我从一个号码到另一个号码,当我遇到一个标有“少数”的号码时,我将计算以下每个号码的所有差异,直到我遇到另一个号码“几个”:

Array         $many    $few
(                 ↓    ↓
    [0] => 1  //  8 -  7 = 1
    [1] => 2  //  9 -  7
    [2] => 3  // 10 -  7
    [3] => 1  // 12 - 11
    [4] => 2
    [5] => 3
    [6] => 4
    [7] => 5
    [8] => 6
    [9] => 7
    [10] => 1
    [11] => 2
    [12] => 3
    [13] => 4
    [14] => 5
    [15] => 6
    [16] => 7
    [17] => 1
    [18] => 1
    [19] => 2
    [20] => 3
    [21] => 4
    [22] => 5
    [23] => 6
    [24] => 1
    [25] => 2
    [26] => 3
    [27] => 1
    [28] => 2
)

因为它是排序的,所以我不必遍历整个... 16 17 18 | 20 21 22 23 24 25 26 | 28 29 30 31 ... exclude | include | exclude 19 (27) - 来自... 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ... ... m m m f m m m m m m m f m m m m ... ↑ ↑ ... ↑ start calculate stop 的每个数字的数字编号。那么我们可以以某种方式考虑到数组是否被排序的事实?或者可能构建包含标记(“f”,“m”)和数字作为键的一个数组? E.g:

$many

1 个答案:

答案 0 :(得分:1)

除了对sort()的两次调用外,您只需要通过$many进行一次循环。

// Input data provided in the question    
$all = range(1, 50);
$few = array(7, 11, 19, 27, 29, 36, 40, 43);
$many = array_values(array_diff($all, $few));

// Display the values to see what we are doing
echo('$few = ['.implode(' ', $few)."]\n");
echo('$many = ['.implode(' ', $many)."]\n");


//
// The actual algorithm starts here


// Sort both $few and $many
// it works fast enough and it is required for the rest of the algorithm
sort($few);
sort($many);

// Be sure the last value of $few is larger than the last value of $many
// This is needed to avoid extra checking for the last element of $few inside the loop
if (end($few) < end($many)) {
    array_push($few, end($many) + 1);
}

// Extract the first two items from $few
$current = array_shift($few);
$next    = array_shift($few);

// This is the result
$differences = array();    

// Run only once through $many, check each item against $next
// subtract $current from it; advance when $next was reached
foreach ($many as $item) {
    // Skip the items smaller than the first element from $few
    if ($item < $current) {
        continue;
    }

    // If the next element from $few was reached then advance to the next interval
    while ($next < $item) {
        $current = $next;
        $next    = array_shift($few);
    }

    // Here $current < $item < $next
    // This echo() is for debug purposes 
    echo('$current = '.$current.'; $item = '.$item.'; $next = '.$next.'; difference='.($item - $current)."\n");

    // Store the difference
    $differences[] = $item - $current;
}