我有一个包含其他关联数组作为其值的数组。这些“子”数组中的每一个都映射有键值对:
$items = [
['type' => 1, 'text' => 'A'],
['type' => 2, 'text' => 'B'],
['type' => 2, 'text' => 'C'],
['type' => 3, 'text' => 'D'],
['type' => 2, 'text' => 'E'],
['type' => 1, 'text' => 'F'],
['type' => 4, 'text' => 'G'],
['type' => 2, 'text' => 'H'],
['type' => 1, 'text' => 'I'],
['type' => 4, 'text' => 'J'],
['type' => 2, 'text' => 'K'],
['type' => 4, 'text' => 'L'],
['type' => 2, 'text' => 'M'],
['type' => 3, 'text' => 'N'],
['type' => 3, 'text' => 'O'],
['type' => 1, 'text' => 'P'],
['type' => 1, 'text' => 'Q'],
['type' => 2, 'text' => 'R'],
['type' => 3, 'text' => 'S'],
['type' => 2, 'text' => 'T'],
['type' => 3, 'text' => 'U'],
['type' => 2, 'text' => 'V'],
['type' => 3, 'text' => 'W'],
['type' => 2, 'text' => 'X'],
['type' => 4, 'text' => 'Y'],
['type' => 2, 'text' => 'Z'],
];
如何对该数组进行排序并作为另一个数组返回,并满足以下要求?
type
对关联数组进行排序。$items
数组中显示的前 3 个项目来完成此操作,然后转到下一个类型,即 2
,并执行相同的操作。我的代码中 types
的最大数量是 8
,但理论上它应该适用于任何数字。1
开始。本质上,你应该得到另一个数组——从上到下——具有交替顺序的值和类型,如下所示:
[
['type' => 1, 'text' => 'A'],
['type' => 1, 'text' => 'F'],
['type' => 1, 'text' => 'I'],
['type' => 2, 'text' => 'B'],
['type' => 2, 'text' => 'C'],
['type' => 2, 'text' => 'E'],
['type' => 3, 'text' => 'D'],
['type' => 3, 'text' => 'N'],
['type' => 3, 'text' => 'O'],
['type' => 4, 'text' => 'G'],
['type' => 4, 'text' => 'J'],
['type' => 4, 'text' => 'L'],
['type' => 1, 'text' => 'P'],
['type' => 1, 'text' => 'Q'],
['type' => 2, 'text' => 'H'],
['type' => 2, 'text' => 'K'],
['type' => 2, 'text' => 'M'],
['type' => 3, 'text' => 'S'],
['type' => 3, 'text' => 'U'],
['type' => 3, 'text' => 'W'],
['type' => 4, 'text' => 'Y'],
['type' => 2, 'text' => 'R'],
['type' => 2, 'text' => 'T'],
['type' => 2, 'text' => 'V'],
['type' => 2, 'text' => 'X'],
['type' => 2, 'text' => 'Z'],
]
text
与排序无关。
我实际上已经制作了一个 YouTube 视频来更好地解释应该发生的事情:Video
我当前的思考过程是使用一个名为
$groups
的单独数组,使用 foreach
循环八次不同的时间,并且在每次循环中,如果不适合特定类型,则继续循环。例如:
// My above $items array example here
// Initialize $groups
$groups = [];
// foreach for type 1
foreach ($items as $item) {
// If any of the items are not of type 1, ignore and continue
if ($item["type"] !== 1) {
continue;
}
// Otherwise, push to $groups
array_push($groups, $item["type"];
}
// foreach for type 2
foreach ($items as $item) {
// If any of the items are not of type 2, ignore and continue
if ($item["type"] !== 2) {
continue;
}
// Otherwise, push to $groups
array_push($groups, $item["type"];
}
// Do this for each possible type, up to type 8
这不仅看起来效率极低而且倒退,我只是觉得有更好的方法来解决这个问题或者我缺少另一个角度。我不相信上面的代码甚至接近解决方案。
我认为设置
array_multisort()
来完成这项工作是合乎逻辑的(因为这是一项排序任务)。array_multisort()
对 $grouper
进行排序,然后对 $column
、$items
进行排序(然后就可以访问 $items
)。$maxConsecutive = 3;
$grouper = [];
$column = [];
foreach ($items as $row) {
$column[] = $row['type']; // preserve isolated type values
$encountered[$row['type']] ??= 0; // declare the default value of 0 for the first encounter of a given type value
$grouper[] = intdiv($encountered[$row['type']]++, $maxConsecutive); // access the cached counter for the given type, divide it by 3, omit any decimal values; then increment the counter (post-incrementation `++` only increases the value AFTER it is used)
}
array_multisort($grouper, $column, $items); // sort by grouper ASC, column ASC, then items ASC
var_export($items);
有些相关的是按循环升序对平面数组进行排序,在按升序循环序列对数据进行排序时,其硬编码分组 N 为 1(而不是 3)。
或者,您可以将数据分组为子集,然后排序,然后在填充新结果时使用分组数据。
不过,我要指出的是,这感觉不像排序任务的
array_multisort()
方法那么专业。
type
值对行进行分组。foreach()
循环(请注意签名中的 &
)仅将每组的前 N 行推入结果数组中。如果当前组还有元素,则将整个组推到数组末尾。代码:(演示)
$maxConsecutive = 3;
$grouped = [];
foreach ($items as $row) {
$grouped[$row['type']][] = $row;
}
ksort($grouped);
$result = [];
foreach ($grouped as &$group) {
array_push($result, ...array_splice($group, 0, $maxConsecutive));
if ($group) {
$grouped[] = $group;
}
}
var_export($result);
作为微优化,您可以使用以下方法提取最后剩余组的整个有效负载:(Demo)
array_push($result, ...array_splice($group, 0, count($grouped) === 1 ? null : $maxConsecutive));
这首先创建每种类型的计数,然后循环直到没有任何输出。内部循环将输出您想要的项目数量(只要该类型还有剩余的内容要输出),然后调整剩余的剩余部分。
我已经评论了代码,应该可以更清楚地解释它。
// Create text lookup array, indexed by type
$types = array_column($items, null, 'type');
// Count the number of each type there are
$breakdown = array_count_values(array_column($items, 'type'));
// Sort by the key to create desired order
ksort($breakdown);
$breakSize = 3;
do {
// If flag doesn't change then nothing is left to output
$anyOutput = false;
foreach ($breakdown as $key => &$countLeft) {
// Loop while less than the break size but also with something left
for ($i = 0; $i < $breakSize && $countLeft > 0; $i++) {
echo $types[$key]['text'] . PHP_EOL;
// Adjust amount left
$countLeft--;
// Flag something put out
$anyOutput = true;
}
}
} while ($anyOutput);
更新: 如果某些类型有不同的文本值,则需要跟踪这些数据。
因此,此代码为每种类型创建一个数组,并为每个类型创建一个文本值列表,然后在循环中,它在每个点从列表中删除第一个(使用
array_shift
)以输出下一个并将其从剩下的名单。
// Split into groups by the type
$breakdown = [];
foreach ($items as $item) {
$breakdown[$item['type']][] = $item['text'];
}
// Sort by the key to create desired order
ksort($breakdown);
$breakSize = 3;
do {
// If flag doesn't changem then run out of content
$anyOutput = false;
foreach ($breakdown as $key => &$textList) {
// Loop while less than the break size but also with something left
for ($i = 0; $i < $breakSize && !empty($textList); $i++) {
echo array_shift($textList) . PHP_EOL;
// Flag something put out
$anyOutput = true;
}
}
} while ($anyOutput);
首先
我似乎找不到一种算法来匹配我想要做的事情。我似乎找不到太多,我开始怀疑我正在寻找的算法是否实际上还不存在
是的,你是对的,它不存在也不应该永远存在,算法不应该存在来输出特定的结果。它应该用于执行特定的行为/功能,而不是实现/输出特定的结果。
uasort
根据数组的键对数组进行排序,如下所示:
$items = [
["type" => 1, "text" => "Type of 1"],
["type" => 1, "text" => "Type of 1"],
["type" => 1, "text" => "Type of 1"],
["type" => 1, "text" => "Type of 1"],
["type" => 2, "text" => "Type of 2"],
["type" => 2, "text" => "Type of 2"],
["type" => 2, "text" => "Type of 2"],
["type" => 2, "text" => "Type of 2"],
];
uasort($items, fn ($a, $b) => $a > $b ? 1 : -1);
print_r($items);
array_column
之类的东西与内爆结合使用,以单线性方式将项目提取为值,或者您可以使用您已经提到的 foreach
循环。