【问题标题】:Futz testing arsort() dependent code?Futz 测试 arsort() 依赖代码?
【发布时间】:2014-09-25 03:59:37
【问题描述】:

似乎一个庞大而复杂的代码库取决于 arsort 生成的顺序。在我深入了解 50 个类中实际发生的情况之前 - 是否有一种简单的方法来随机播放具有相同值的项目?

换句话说,如果输入是

['foo' => 3, 'bar' => 3, 'baz' => 3, 'this' => 2,  'that' => 2]

我想买

['baz' => 3, 'bar' => 3, 'foo' => 3, 'this' => 2,  'that' => 2]

可能会跑一次,然后

['baz' => 3, 'bar' => 3, 'foo' => 3, 'that' => 2,  'this' => 2]

在另一个随机运行中。

【问题讨论】:

  • 那些是重复的键
  • 我第二个@Ghost - 对于洗牌数组,你应该使用Fisher Yates算法:stackoverflow.com/questions/3169805/…
  • @Ghost 对不起,我试图举一个简单的例子。固定。
  • @Centril 但我绝对不想要相同的订单,我希望所有可能的订单都发生在后续运行中。
  • 据我从您的示例中了解到,您希望将集合 {baz,bar,foo} 和 {that,this} 相互独立地洗牌......洗牌不能保证所有可能的订单将包括在内,但最终可能会发生。

标签: php arrays


【解决方案1】:

这样的事情怎么样? (未经测试)

最坏情况复杂度:O(k)

注意:为 算法清晰 而不是 PHP 细节...

function shuffleInput( $data ) {
    // Separate into sets.
    $sets = [];
    foreach ( $data as $k => $v ) {
        $sets[$v][] = $k;
    }

    // Shuffle & Join.
    $data = [];
    foreach ( $sets as $v => &$set ) {
        shuffle( $set );
        foreach( $set as $k ) {
            $data[$k] = $v;
        }
    }
    return $data;
}

根据您输入的大小,最好在第一个循环中取消设置 $data 中的每个元素,而不是仅仅创建一个新数组。这适用于数据非常大且内存对您来说很宝贵的情况 - 以及减少内存使用的任何突然高峰和低谷。

此外,如果您要不断地改变相同的 $data,您可能希望将 $sets 的制作分开到其他地方,或者至少允许开发人员将其作为副作用传递/获取。

【讨论】:

  • 洗牌后你可以用call_user_func_array('array_merge', $set)代替foreach。
  • 不,你不能因为 $set 是“类型”数组[index => $k] 而不是你需要的 [$k => $v]。此外,如果你想调用 array_merge ,你可以在没有多余的反射的情况下做到这一点。我相信我所拥有的是最有效的方法......可能的改进:让 C 调用 foreach 所做的事情 - 即:array_add($dest, $keys, $value_for_all);另外:在 foreach 中提供 array_pop 方法并访问密钥,以便在到达重置行时使 $data 已经为空。
【解决方案2】:

如果您不想处理随机播放,而是更喜欢检查数组的所有排列,那么您可以执行以下操作:

$arr = array('foo' => 3, 'bar' => 3, 'baz' => 3, 'this' => 2,  'that' => 2);
$keys = array_keys($arr);
$indexes = range(0, count($arr) - 1);

pc_permute($indexes, $perms);

var_dump($perms);

function pc_permute($items, &$ret = array(), $perms = array( )) {
    if (empty($items)) { 
        $ret[] = $perms;
    }  else {
        for ($i = count($items) - 1; $i >= 0; --$i) {
             $newitems = $items;
             $newperms = $perms;
             list($foo) = array_splice($newitems, $i, 1);
             array_unshift($newperms, $foo);
             pc_permute($newitems, $ret, $newperms);
         }
    }
}

Array $perms 将给出索引的所有排列,您可以从 $keys 中获取索引的键名,以及从 $arr 获取的键或索引值(使用 array_slice):)

ps:但你应该明白 - 你在原始数组中有更多的元素,你会发现更多的排列。如果有n个元素,那么就会有n个!排列。对于 n = 5,有 120 个排列。

【讨论】:

  • 哎呀,这是一个有趣的想法,但由于 O(n!) 有点无法使用 ^^
猜你喜欢
  • 1970-01-01
  • 2016-02-04
  • 1970-01-01
  • 2014-10-10
  • 2012-01-01
  • 2021-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多