合并PHP数组

时间:2011-08-18 11:26:28

标签: php arrays

如果除startdate之外的所有值都相同,我想要合并多个关联数组。如果两个数组确实相同,我想合并它们并创建一个新元素enddate,以便startdateenddate显示日期范围。范围内的所有日期必须以原始数组表示,即如果缺少日期,则不得合并其任何一侧的日期。

Array('color'=>'red','size'=>'large','shape'=>'circle','startdate'=>'2011-08-17')
Array('color'=>'red','size'=>'large','shape'=>'circle','startdate'=>'2011-08-18')
Array('color'=>'red','size'=>'large','shape'=>'square','startdate'=>'2011-08-20')

应该成为:

Array('color'=>'red','size'=>'large','shape'=>'circle','startdate'=>'2011-08-17','enddate'=>'2011-08-18')
Array('color'=>'red','size'=>'large','shape'=>'square','startdate'=>'2011-08-20')

到目前为止,我已经尝试循环遍历每个数组并创建一个多维数组:

foreach($arrays as $id => $array){
    $mergearray[$array['red']][$array['large']][$array['circle']] = $id;
};

以检查另一个数组是否具有相同的值。我正在尝试使用这些数组来重建原始结构中的数组。

5 个答案:

答案 0 :(得分:1)

避免日期/日期功能浪费cpu时间,没有额外的好处(Dave回答)。 避免使用海量数组函数(来自adlawson的回答),同样浪费时间,只需订购数组并处理智能方式会更快。

但大多数情况下,你想要做什么,为什么那些数组就像那样......那背后有一个SQL吗?

因为如果存在,那么解决方案比尝试合并格式错误的数组要简单得多(尽管如此,你所寻求的转换意味着在某些时候出现了问题...... start_time成为end_time表示尝试保留一个完整的项目历史,在PHP本身没有地位imho)。

如果真的是你需要的话,我会给你正确的PHP代码,但我很怀疑这是你申请的正确方法。

答案 1 :(得分:0)

这样的事情可以解决问题:

$newArray = array();
$newLine = false;
$prev_day = false;
foreach ($array as $line) {
    $this_day = strtotime($line['startdate']);
    if (($newLine) && ($prev_day == strtotime('-1 day', $this_day))) {
        $newLine['enddate'] = $line['startdate'];
        $newArray[] = $newLine;
        $newLine = false;
    } elseif (!$newLine) {
        $newLine = $line;
    }
    if ($newLine) {
        $newLine['enddate'] = $line['startdate'];
    }
    $prev_day = $this_day;
}
$newArray[] = $newLine;

答案 2 :(得分:0)

我看不到这种合并的实际实现,但这应该有效。它可能看起来很长,但它会照顾好一些事情。

/**
 * @example array_merge_allbutstartdate($array1, $array2, $array3, $array4, $arr...)
 * @param array $array1
 * @param array $array2, $arr...
 * @return array
 */
function array_merge_allbutstartdate(array $array1, array $array2)
{
    $out  = array();
    $date = array();
    $startKey = 'startdate';
    $endKey   = 'enddate';

    foreach (func_get_args() as $item) {
        if (!is_array($item)) {
            trigger_error('All arguments should be an array.', E_USER_ERROR);
        }

        $temp = null;
        if (isset($item[$startKey])) {
            $temp = $item[$startKey];
            unset($item[$startKey]);
        }

        if (!in_array($item, $out)) {
            $i = count($out);
            $out[] = $item;
        } else {
            $i = array_search($item, $out);
        }

        if (null !== $temp) {
            $date[$i][] = $temp;
        }
    }

    foreach ($date as $j => $row) {
        array_map('strtotime', $row);
        $start = array_search(min($row), $row);
        $end = array_search(max($row), $row);

        // Add start date
        $out[$j][$startKey] = $date[$j][$start];

        // Only add end date if it is not equal to start date
        if ($date[$j][$start] !== $date[$j][$end]) {
            $out[$j][$endKey] = $date[$j][$end];
        }
   }

    return $out;
}

答案 3 :(得分:0)

鉴于你已经拥有了一个数组数组,你实际上要做的是删除连续的条目(除了每个时间跨度的第一个条目)。

您的算法将是:

$expected_start_time= 0; // initial val
foreach($all_entries as $k => &$v) {
    $start_time = strtotime($v['startdate']);
    if($start_time != $expected_start_time) {
        $range_start =& $v; // this is a range beginning. Put end date in here
    } else {
        $range_start['enddate'] = $v['startdate'];
        unset($all_entries[$k]);
    }
    $expected_date = strtotime('+1 day', $start_time);
}

这基本上是Dave Child答案的一个更小的,就地版本。

答案 4 :(得分:0)

function group_and_sort($data)
{
    $out = array();
    while($data) {

        // Shift off the first element
        $buffer = array_shift($data);
        $end_date = $buffer['startdate'];

        // Try to group successive elements...
        while($data) {

            // Case 1: Does the next element differ by more than just date?
            if(count(array_diff_assoc($buffer, $data[0])) > 1) {
                break;
            }

            // Case 2: Does the next element have an unexpected date?
            $expected_date = date('Y-m-d', strtotime('+1 day', strtotime($end_date)));
            if($data[0]['startdate'] != $expected_date) {
                break;
            }

            // Otherwise, push end_date forward and throw away the element
            $end_date = $data[0]['startdate'];
            array_shift($data);
        }

        // If the dates differ, record the range.
        if($buffer['startdate'] != $end_date) {
            $buffer['enddate'] = $end_date;
        }

        $out[] = $buffer;
    }

    return $out;
}

假设元素已按日期排序。如果他们不是,你可以使用:

function sort_startdate($a, $b)
{
    return strcmp($a['startdate'], $b['startdate']);
}
usort($data, 'sort_startdate');

将其传递给group_and_sort($data)