在具有数值的数组中,选择一个范围内的连续值,并将其全部设置为其中的最高值


In an array with numeric values, select the successive values within a range and set them all to the highest value of them

所有这些都在关联数组中。

我有一个数组,它保存一些ID作为键,保存一些整数作为值:

array([24]=>1620, [49]=>1620, [35]=>1622, [101]=>1623, [214]=>1630, [50]=>1638, [5]=>1640)

我想要获得的是,当"LastValue-FirstValue<=4"时,将所有接近值设置为其中的最高值,如下所示:

array([24]=>1623, [49]=>1623, [35]=>1623, [101]=>1623, [214]=>1630, [50]=>1640, [5]=>1640)

事实上是关于一些有计划日期的事件;该计划日期被存储为周号;我想把一个月内到最后一周的连续个人项目分组。

所以我创建了这个数组,其中包含事件的ID和日期;数组按值升序排列。但我不知道如何在一个月内对连续的单个值进行分组,将它们设置为最高值(最后一个),然后传递到下一个值,识别组,设置值,等等

有什么建议吗?谢谢

当您有一系列没有间隔的长周时,您描述的方法是不明确的。在这种情况下,有几种方法可以将几周分组在一起,保持分组的第一周和最后一周的间隔不应超过4周。

假设你不期望有这么长的一系列不间断的周数,我在这里提出了一个算法,它可以向后遍历(排序的)事件数组。它暂时将周数转换为"绝对"周数,每年不会重置为1,而是不断增加。这样,算法就可以同样地找到跨越年份界限的组:

// Sample data
$data = array(24=>1620, 49=>1620, 35=>1622, 101=>1623, 214=>1630, 50=>1638, 5=>1640);
$last_abs_week = 99999;
$date = new DateTime();
// first week in the "absolute" week numbering:
$ref_date = new DateTime();
$ref_date->setISODate(2000, 1);
// Loop backwards:
foreach (array_reverse(array_keys($data)) as $event) {
    $week = $data[$event];
    // Get date corresponding to week number
    $date->setISODate("20" .  substr($week, 0, 2),  substr($week, 2));
    // Convert date to number of weeks since year 2000 to allow week numbers
    // to be subtracted even when belonging to different years
    $abs_week = $date->diff($ref_date)->format("%a") / 7;
    if ($abs_week < $last_abs_week - 4) {
        // Not within same group: start a new group
        $last_week = $week;
        $last_abs_week = $abs_week;
    } else {
        // In same group: assign last week of group
        $data[$event] = $last_week;
    }
}
print_r ($data);

样本数据的输出为:

Array
(
    [24] => 1623
    [49] => 1623
    [35] => 1623
    [101] => 1623
    [214] => 1630
    [50] => 1640
    [5] => 1640
)

正向搜索

这里有一种替代方法,按照给定的顺序扫描阵列:

$first_abs_week = 0;
$group = [];
$date = new DateTime();
$ref_date = new DateTime();
$ref_date->setISODate(2000, 1);
foreach ($data as $event => $week) {
    // Get date corresponding to week number
    $date->setISODate("20" .  substr($week, 0, 2),  substr($week, 2));
    // Convert date to number of weeks since year 2000 to allow week numbers
    // to be subtracted even when belonging to different years
    $abs_week = $date->diff($ref_date)->format("%a") / 7;
    if (count($group) && $abs_week > $first_abs_week + 4) {
        $week = $data[array_pop($group)];
        foreach ($group as $prev_event) {
            $data[$prev_event] = $week;
        }
        $group = [];
        $first_abs_week = $abs_week;
    }
    $group[] = $event;
}
print_r ($data);

示例数据的输出与第一个备选方案的输出相同。