首先封装一个class InterlacePageHelper 编写两个方法:一个是计算当前页的数据结构(pageInterlace),一个是列表数据构建(dataInterlace)
/**
* 计算分页之间的穿插
* 参数说明:第一个列表总长度、第二个列表总长度、页码、页数量、第一个列表穿插长度、第二个列表穿插长度
*/
public static function pageInterlace($beforeCount, $afterCount, $page, $pageSize, $beforeNumber, $afterNumber)
{
if (ceil(($beforeCount + $afterCount) / $pageSize) < $page) {
return false;
}
$step_number = $beforeNumber + $afterNumber;
$total_offset = ($page - 1) * $pageSize;
$total_current = $page * $pageSize;
$step_y = $total_offset % $step_number;
$total_y = $total_current % $step_number;
$step = floor($total_offset / $step_number);
$offset_before_step = $offset_after_step = $step;
$before_start_bool = false;
$after_start_bool = false;
if ($step_y > $beforeNumber) {
$after_start_bool = true;
$offset_before_step = $offset_before_step + 1;
$offset_before = $offset_before_step * $beforeNumber;
$offset_after = ($offset_after_step * $afterNumber) + ($step_y - $beforeNumber);
} else {
if ($step_y != $beforeNumber) {
$before_start_bool = true;
} else {
$after_start_bool = true;
}
$offset_before = $offset_before_step * $beforeNumber + $step_y;
$offset_after = $offset_after_step * $afterNumber;
}
$total_step = floor($total_current / $step_number);
$limit_before_step = $limit_after_step = $total_step;
if ($total_y > $beforeNumber) {
$limit_before_step = $limit_before_step + 1;
$limit_before = $limit_before_step * $beforeNumber;
$limit_after = ($limit_after_step * $afterNumber) + ($total_y - $beforeNumber);
} else {
$limit_before = $limit_before_step * $beforeNumber + $total_y;
$limit_after = $limit_after_step * $afterNumber;
}
$limit_before = $limit_before - $offset_before;
$limit_after = $limit_after - $offset_after;
$before_start_number = 0;
$after_start_number = 0;
if ($before_start_bool) {
$before_start_number = $beforeNumber - $step_y;
}
if ($after_start_bool) {
$after_start_number = $afterNumber - ($step_y - $beforeNumber);
}
if (!$before_start_bool && !$after_start_bool) {
$before_start_bool = true;
}
if ($beforeCount < $offset_before && $afterCount < $offset_after) {
$offset_before = $beforeCount;
$offset_after = $afterCount;
$limit_before = 0;
$limit_after = 0;
} elseif ($beforeCount < $offset_before && ($afterCount > $offset_after && $afterCount < $offset_after + $limit_after)) {
$offset_before = $beforeCount;
$offset_after = $total_offset - $offset_before;
$limit_before = 0;
$limit_after = $pageSize;
} elseif ($beforeCount < $offset_before && $afterCount > $offset_after + $limit_after) {
$offset_before = $beforeCount;
$offset_after = $total_offset - $offset_before;
$limit_before = 0;
$limit_after = $pageSize;
} elseif (($beforeCount > $offset_before && $beforeCount < $offset_before + $limit_before) && $afterCount < $offset_after) {
$offset_before = $total_offset - $offset_after;
$offset_after = $afterCount;
$limit_before = $pageSize;
$limit_after = 0;
} elseif (($beforeCount > $offset_before && $beforeCount < $offset_before + $limit_before) && ($afterCount > $offset_after && $afterCount < $offset_after + $limit_after)) {
$limit_before = $beforeCount - $offset_before;
$limit_after = $afterCount - $offset_after;
} elseif (($beforeCount > $offset_before && $beforeCount < $offset_before + $limit_before) && $afterCount > $offset_after + $limit_after) {
$limit_before = $beforeCount - $offset_before;
$limit_after = $pageSize - $limit_before;
} elseif ($beforeCount > $offset_before + $limit_before && $afterCount < $offset_after) {
$offset_before = $total_offset - $offset_after;
$offset_after = $afterCount;
$limit_before = $pageSize;
$limit_after = 0;
} elseif ($beforeCount > $offset_before + $limit_before && ($afterCount > $offset_after && $afterCount < $offset_after + $limit_after)) {
$limit_after = $afterCount - $offset_after;
$limit_before = $pageSize - $limit_after;
}
if ($limit_before == 0) {
$after_start_bool = true;
$after_start_number = $limit_after;
}
if ($limit_after == 0) {
$before_start_bool = true;
$before_start_number = $limit_before;
}
return [
'page' => $page,
'pageSize' => $pageSize,
'step_before' => $beforeNumber,
'step_after' => $afterNumber,
'offset_before' => $offset_before,
'offset_after' => $offset_after,
'limit_before' => $limit_before,
'limit_after' => $limit_after,
'before_start_bool' => $before_start_bool,
'after_start_bool' => $after_start_bool,
'before_start_number' => $before_start_number,
'after_start_number' => $after_start_number,
];
}
接着数据列表按照计算–数据按照穿插进去成为一个新的列表
/**
* 数据按照穿插进去成为一个新的列表
*/
public static function dataInterlace($beforeList, $afterList, $interlaceResult)
{
$new_list = [];
//先看谁先开始--把头放进去
$before_offset = 0;
$after_offset = 0;
$beforeListCount = count($beforeList);
$afterListCount = count($afterList);
//虽然下面逻辑是处理好了--但是列表如果有空的还是处理一下
if ($beforeListCount == 0 || $afterListCount == 0) {
return $beforeListCount == 0 ? $afterList : $beforeList;
}
for ($i = 1; $i < $interlaceResult['pageSize']; $i++) {
if ($before_offset + $after_offset >= $interlaceResult['pageSize'] || count($new_list) == ($beforeListCount + $afterListCount)) {
break;
}
if ($i == 1) {
if ($interlaceResult['before_start_bool']) {
$before_start_number = $interlaceResult['before_start_number'] == 0 ? $interlaceResult['step_before'] : $interlaceResult['before_start_number'];
$before_item = array_slice($beforeList, $before_offset, $before_start_number);
$new_list = array_merge($new_list, $before_item);
$before_offset = $before_offset + $before_start_number;
$after_item = array_slice($afterList, $after_offset, $interlaceResult['step_after']);
$new_list = array_merge($new_list, $after_item);
$after_offset = $after_offset + $interlaceResult['step_after'];
}
if ($interlaceResult['after_start_bool'] && $interlaceResult['after_start_number'] > 0) {
$after_item = array_slice($afterList, $after_offset, $interlaceResult['after_start_number']);
$new_list = array_merge($new_list, $after_item);
$after_offset = $after_offset + $interlaceResult['after_start_number'];
}
continue;
}
if ($before_offset < $beforeListCount) {
$before_item = array_slice($beforeList, $before_offset, $interlaceResult['step_before']);
$new_list = array_merge($new_list, $before_item);
$before_offset = $before_offset + $interlaceResult['step_before'];
}
if ($after_offset < $afterListCount) {
$after_item = array_slice($afterList, $after_offset, $interlaceResult['step_after']);
$new_list = array_merge($new_list, $after_item);
$after_offset = $after_offset + $interlaceResult['step_after'];
}
}
return $new_list;
}
示例:
这里我使用的是Yii2.0框架,调用示例:
//获取两个列表穿插数据的总数
$before_count = $before_query->count();
$after_count = $after_query->count();
//参数说明:第一个列表总长度、第二个列表总长度、页码、页数量、第一个列表穿插长度、第二个列表穿插长度
$interlace_result = InterlacePageHelper::pageInterlace($before_count, $after_count,$this->searchParams['page'], $this->searchParams['pageSize'], 3, 3);
$before_list = $before_query->offset($interlace_result['offset_before'])
->limit($interlace_result['limit_before'])
->orderBy('last_active_date desc,rl.id asc')
->asArray()
->all();
$after_list = $after_query->offset($interlace_result['offset_after'])
->limit($interlace_result['limit_after'])
->orderBy('last_active_date desc,rl.id asc')
->asArray()
->all();
$list = InterlacePageHelper::dataInterlace($before_list, $after_list, $interlace_result);
//获取到当前页的列表数据
return $list;