我有一个数组,它包含其他关联数组作为它的值.这些"子"数组中的每一个都使用键-值对进行映射:

$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'],
];

如何对此数组进行排序并返回为另一个数组,并满足以下要求?

  1. 它需要按其type对关联数组进行排序.
  2. 它需要 Select 显示在$items数组中的前3项,然后移到下一种类型,即2,并执行相同的操作.在我的代码中,types的最大值是8,但理论上它应该适用于任何数字.
  3. 如果它一次 Select 了每种类型的3个,则使用数组中的其余项再次重新启动,再次从类型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

我目前的 idea 是使用一个名为$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

这不仅看起来非常低效和倒退,我只是觉得有更好的方法来做,或者从另一个我错过的Angular go 做.我不相信上面的代码接近解决方案.

推荐答案

我认为设置array_multisort()人来做这项工作是合乎逻辑的(因为这是一项分类任务).
请注意,我的演示将对实际输入数组进行排序(如果需要保留原始数组,请复制一份).

  1. 迭代输入array.
  2. 用递增的分组id填充平面映射array.
  3. 填充类型值的平面映射array.
  4. 调用array_multisort()$grouper上排序,然后是$column,然后是$items(然后您可以访问$items).

电话号码:(Demo)(Alt Demo)

$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);

有些相关的是Sort a flat array in recurring ascending sequences,它在按递归升序对数据进行排序时,硬编码组N为1(而不是3).


或者,您可以将数据分组为子集,然后在填充新结果时排序,然后使用分组的数据.
不过,我要说的是,对于排序任务,这感觉不像array_multisort()的方法那么专业.

  1. 按行的type值对行进行分组.
  2. 按新的第一级键排序.
  3. 使用自扩展foreach()循环(请注意签名中的&)将每个组的前N行压入结果array.如果当前组仍有元素,则将整个组推到数组的末尾.

代码:(Demo)

$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));

Php相关问答推荐

无法使用PHP DomDocument找到IMG元素

如何在Livewire中验证多个 Select 字段

按制造商、型号和年份范围判断数据的存在性

Laravel POST方法返回状态:POST方法上不允许使用405方法

WordPress插件和JSON不是有效的响应错误

有没有可能从composer 过时的输出中隐藏不需要的主要版本?

使用PHP编码的字符串与使用OpenSSL编写的shell 代码之间的差异

Symfony5:如何在不登录的情况下使API路由可访问?

从AJAX响应中获取一个未定义的html

拉威尔10有许多通过获取所有祖父母数据的子元素S图像

关于Laravel缓存出现的错误

根据页面以及是否在促销,向 WooCommerce 中显示的价格添加前缀

为什么 php 只能在我的 Nginx Web 服务器的某些目录中工作?

使用用户元数据填写 woocommerce checkout 字段

PHP 在数组中搜索值

跟踪通过 WooCommerce 分层定价表插件进行的购买

PHP for each 函数打印 td

如何将 2021-04-08T22:25:09.335541Z 作为时间戳保存到 Laravel 中的数据库中?

getenv() 有时在 CodeIgniter 4 中返回 false.为什么?

如何将文件直接上传到 Cloudinary 而不先保存在 public 文件夹中