【问题标题】:Sorting an array based on a condition根据条件对数组进行排序
【发布时间】:2013-09-30 05:04:58
【问题描述】:

我有以下数组

$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 的方式对这个数组进行排序。

示例:上述数组中“grids”的值为:6,3,6,3,3,12,3

(6+6=12), (3+3+3+3=12),(12=12) 所以新订单应该是6,6,3,3,3,3,12 or 3,3,3,3,12,6,6 or 6,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 来实现吗?

更新

grid 的值将始终为 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"),

 );

【问题讨论】:

  • 这没有灵丹妙药,它需要你从头开始编写一个相当广泛的函数。
  • ID 1、2、4、3、5、7、6 也可以接受吗?哪个是首选?
  • 任意数量的背靠背“网格” => 那应该是什么意思?
  • 您可能无法使用 php 的排序函数来执行此操作,因为这些函数假定有一种方法可以比较两个对象并确定哪个对象更大或更小。在您的示例中,您没有一个对象大于或小于另一个对象的概念。相反,您尝试根据它们的网格值加起来为 12 进行分组。
  • @WolfgangStengel ID 在这里不是问题 :) 感谢您的回复

标签: php sorting multidimensional-array


【解决方案1】:

所以你并没有真正排序,而是重新排序以创建序列。我想您正在尝试对具有固定高度的砖块进行布局,并且您需要对其重新排序以填充每一行并将其余部分留在最后。对于给定的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;
}

【讨论】:

  • 您是如何理解我正在尝试创建布局的?这正是我想要做的:)。降序真的产生了一个无聊的布局。您的代码非常智能,可以产生我真正想要的东西。可能是我无法清楚地解释我的问题中的所有内容,但是您以某种方式理解它并为我开发了一个超级代码。您的代码不仅仅是通过升序/降序进行排序,而是进行真正的计算以找出可用于创建漂亮模板布局的序列。我不能感谢你足够的人。你帮了我很多。你是个天才。 :)
  • 请检查我问题的“问题”部分。如果我使用问题部分中显示的数组,我会得到重复的值。谢谢
  • 嗯,这是一个快速而肮脏的概念证明,错误是意料之中的。我修复了它,但它不是生产级代码,所以我鼓励你自己实现它:)
【解决方案2】:

问题是:

我想以一种方式对这个数组进行排序,即任意数量的总和 to back "grids" 等于 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"),
);

您有号码34 次,号码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
    )

)

【讨论】:

  • 是的,网格的结果应该是 12。您的比较不会这样做,而只是从最低到最高排序
  • 是的,我想你是对的,但我确信答案没有帮助。如果 OP 只对这个特定数组感兴趣,他会手动排序一次并完成它。拥有 25k 声望,你一定是在开玩笑 :)
  • 我很抱歉,确实你只需要对我能想到的所有示例进行降序排序即可获得所需的结果。不知何故,我认为 9 也应该是可能的(因为它是 3 的倍数),但 OP 明确排除了这一点。荣誉。
  • @SheikhHeera 非常感谢您的帮助,也感谢 Wolfgang Stengel :)
  • 是的,你的回答和 Wolfgang Stengel 的回答都对我有用,我接受了你的回答,因为你先回答了这个问题 :) 非常感谢 :) 我希望我能像你们一样成为 PHP 专家
【解决方案3】:

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

$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,所有其他组合都被剩余的三点填满。 (出于某种原因,我认为算法也必须能够处理 9。)所以这就是你所需要的:

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

当然,这是一个非常无聊的网格。

【讨论】:

  • 非常感谢您的回答。您能否告诉我如何使用您的解决方案,因为print_r($records); 没有给我任何结果:)
  • 记录放入$grouped
  • 请想象一个像这样的序列6,3,3,3,6,6如果你按照我想要的方式排序它应该是这样6,6,3,3,6,3(6+6 =12 3+3+6= 12, 3 is remaing)但是你的代码只是像这样排序3,3,3,6,6,6跨度>
【解决方案4】:

在 PHP >= 5.3.0 中,您可以使用 usort() 和闭包(或作为 hack 的全局变量)来执行此操作。给定$records

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

如果您将“网格”参数可视化为字符串长度,则最终结果 $records 的排序如下:

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

鉴于可用块的随机性,您可能希望首先从小到大对该数组进行排序,然后查看它是否为您安排得更好。这种方法显然不会检测到不适合 --- 或无法解析适合的碎片和块。

【讨论】:

  • 这到底是怎么工作的? ;-) 你不应该知道数组元素传递给比较函数的顺序吗?
猜你喜欢
  • 2018-11-01
  • 2012-02-11
  • 2021-03-08
  • 1970-01-01
  • 2022-08-15
  • 1970-01-01
  • 2012-12-01
  • 1970-01-01
  • 2019-09-01
相关资源
最近更新 更多