根据条件对数组进行排序


Sorting an array based on a condition

>我有以下数组

$records = array(
    array("postId"=>"1","grid"=>"6"),
    array("postId"=>"2","grid"=>"3"),
    array("postId"=>"3","grid"=>"6"),
    array("postId"=>"4","grid"=>"3"),
    array("postId"=>"5","grid"=>"3"),
    array("postId"=>"6","grid"=>"12"),
    array("postId"=>"7","grid"=>"3"),
);

我想以任意数量的背靠背"网格"之和等于 12 的方式对这个数组进行排序。

示例:上面数组中"网格"的值为:6,3,6,3,3,12,3

(6+6=12), (3+3+3+3=12),(12=12) 所以新订单应该是6,6,3,3,3,3,123,3,3,3,12,6,66,3,3,6,3,3,12

因此,对数组进行排序后,新数组应如下所示:

$records=array(
    array("postId"=>"1","grid"=>"6"),
    array("postId"=>"3","grid"=>"6"),
    array("postId"=>"2","grid"=>"3"),       
    array("postId"=>"4","grid"=>"3"),
    array("postId"=>"5","grid"=>"3"),
    array("postId"=>"7","grid"=>"3"),
    array("postId"=>"6","grid"=>"12"),
);

我在php手册中搜索并找到了这些功能:sort,uasort,uksort,usort,但我不知道如何使用它们。

你能告诉我如何使用PHP实现这一点吗?

更新

网格的值将始终为 3 或 6 或 12(仅这三个数字)

问题

  $records = array(
    array("postId"=>"1","grid"=>"3"),
    array("postId"=>"2","grid"=>"6"),    
    array("postId"=>"3","grid"=>"3"),     
    array("postId"=>"4","grid"=>"3"),
    array("postId"=>"5","grid"=>"6"),
    array("postId"=>"6","grid"=>"6"),    
    array("postId"=>"7","grid"=>"3"),
    array("postId"=>"8","grid"=>"6"),
 );

所以你不是真正的排序,而是重新排序以创建序列。我想您正在尝试对固定高度的砖进行一些布局,并且需要对其进行重新排序以填充每一行,并将其余部分留在最后。对于给定的固定变体12,6,3可以通过按降序排序来完成 - 对于奇数个六,它将填充较小的三。然而,这样的顺序会产生无聊的布局 - 为了让它更有趣,你只需要重新排序一些帖子。为此,您需要创建临时容器,并在其网格之和等于 12 时合并它。如果您留下了一些临时容器,请将它们合并为一个并按降序排序,然后再与之前分组的容器合并。

说明我的概念的代码:

//auxiliary function to calculate sum of grids in given temporary container
    function reduc($a) {
    return array_reduce($a, function ($result, $item) {
        return $result . $item['grid'] . ',';
    }, '');
}
function regroup($records, $group_sum = 12) {
    $temp = array();
    $grouped = array();
    foreach ($records as $r) {
        if ($r['grid'] == $group_sum) {
            $grouped[] = $r;
        } else {
            if (!$temp) {
                $temp[] = array($r);
            } else {
                $was_grouped = false;
                foreach ($temp as $idx => $container) {
                    $current_sum = sum_collection($container);
                    if ($current_sum + $r['grid'] <= $group_sum) {
                        $temp[$idx][] = $r;
                        if ($current_sum + $r['grid'] == $group_sum) {
                            $grouped = array_merge($grouped, $temp[$idx]);
                            unset($temp[$idx]);
                        }
                        $was_grouped = true;
                        break;
                    }
                }
                if (!$was_grouped) {
                    $temp[] = array($r);
                }
            }
        }
    }
    if ($temp) {
        //Sort descending, so biggest ones will be filled first with smalller
        $rest = call_user_func_array('array_merge', $temp);
        usort($rest, function($a, $b) {
            return $b['grid'] - $a['grid'];
        });
        $grouped = array_merge($grouped, $rest);
    }
    return $grouped;
}

问题是:

我想以一种任意数量的返回之和的方式对这个数组进行排序 返回"网格"等于 12。

你可以试试这个(使用usort)

$records = array(
    array("postId"=>"1","grid"=>"6"),
    array("postId"=>"2","grid"=>"3"),
    array("postId"=>"3","grid"=>"6"),
    array("postId"=>"4","grid"=>"3"),
    array("postId"=>"5","grid"=>"3"),
    array("postId"=>"6","grid"=>"12"),
    array("postId"=>"7","grid"=>"3"),
);

你有 4 次3,敏捷6 2 次,12一次。

// Sort (ASC)
usort($records, function($a, $b) {
    return $a['grid'] - $b['grid'];
});

DEMO-1 (ASC) ( 3+3+3+3=126+6=1212=12 )。

// Sort (DESC)
usort($records, function($a, $b) {
    return $b['grid'] - $a['grid'];
});

DEMO-2 (DESC) ( 12=126+6=123+3+3+3=12 )。

排序后输出 (ASC) :

阵列 (

[0] => Array
    (
        [postId] => 7
        [grid] => 3
    )
[1] => Array
    (
        [postId] => 5
        [grid] => 3
    )
[2] => Array
    (
        [postId] => 4
        [grid] => 3
    )
[3] => Array
    (
        [postId] => 2
        [grid] => 3
    )
[4] => Array
    (
        [postId] => 3
        [grid] => 6
    )
[5] => Array
    (
        [postId] => 1
        [grid] => 6
    )
[6] => Array
    (
        [postId] => 6
        [grid] => 12
    )

此解决方案首先按网格大小降序排序,然后通过根据到目前为止每行的总和测试每个剩余元素来暴力强制它下降:

$sum=0;
$grouped=array();
usort($records, function($a, $b) { return $a['grid']<$b['grid']; });
while ($records)
{
    $next=reset($records);
    if ($sum) foreach ($records as $next) if ($sum+$next['grid']<=12) break;
    $grouped[]=$next;
    $sum+=$next['grid'];
    unset($records[array_search($next, $records)]);
    if ($sum>=12) $sum=0;
}

更新

事实证明,按降序排序足以仅使用 3、6 和 12 个元素来解决需求。一个 12 和一个 6 和一个 6 独立站立,所有其他组合都用剩余的三分填满。(出于某种原因,我认为算法也必须能够处理九。所以这就是你所需要的:

usort($records, function($a, $b) { return $a['grid']<$b['grid']; });

当然,这使得网格非常无聊。

在 PHP>= 5.3.0 中,您可以使用 usort() 和闭包(或全局变量作为黑客)来做到这一点。给定$records

$running_length = 0;
usort( $records, function( $a, $b ) use( $running_length ) {
    $running_length += $a["grid"];
    if( $running_length >= 12 ) return( true );
    return( false );
});

如果将"grid"参数可视化为字符串长度,则最终结果$records 将按如下顺序排列:

...            3
...            3
......         6
...                3
......             6
...                3
............  12

给定可用块的随机性,您可能希望首先从最小到最大对数组进行排序,然后查看它是否更适合您。此方法显然无法检测到不适合---或无法解析为适合的碎片和块。