如何改造这个阵列?

时间:2012-06-29 15:59:26

标签: php arrays

这是数据

$array = array(
    'random' => 1,
    'pewpew' => 2,
    'temp' => 5,
    'xoxo' => 3,
    'qweqweqe' => 4,
);

$fields = array('random', 'xoxo', 'temp');

我需要得到结果:

$result = array(
    'random' => 1,
    'xoxo' => 3,
    'temp' => 5,
);

我的意思是来自$ fields的密钥存在/订单适用于$ array。

问题是: 我可以仅使用array_函数执行此转换吗? (我不想使用迭代) 如果是:你能链接我需要的功能吗?

(对不起拼写错误)

UPD。

PHP 5.2

14 个答案:

答案 0 :(得分:5)

$result=array_intersect_key($array ,array_flip($fields) );

答案 1 :(得分:3)

// little trick required here...
$fields = array('random' => 0, 'xoxo' => 0, 'temp' => 0);
$result = array_intersect_key($array,$fields);

答案 2 :(得分:2)

我一直对这些类型的问题感兴趣,其中包括 高效代码 (在代码使用和速度方面)。也就是说,我试过并基准几种不同的方法,没有什么是有效的和简单的foreach

我尝试了所有发布的解决方案,以及我自己的array_walk和基本的foreach。我运行了几个测试,包括Miraage发布的数组和字段,还有一些包含更大的数组。我还注意到结果有些奇怪,例如,如果$ fields的值不在$ array中,则为其他值。

我已经快速订购了。

前:0.01245秒

$result = array();
foreach ($fields as $k)
{
    if (isset($array[$k]))
        $result[$k] = $array[$k];
}

ARRAY_DIFF_KEY:0.01471秒(意外结果:其他值)

$result = array_diff_key($fields, $array);

FOREACH(功能):0.02449秒

function array_filter_by_key($array, $fields)
{
    $result = array();
    foreach ($fields as $k)
    {
        if (isset($array[$k]))
            $result[$k] = $array[$k];
    }

    return $result;
}

ARRAY_WALK(按参考文献):0.09123秒

function array_walk_filter_by_key($item, $key, $vars)
{
    if (isset($vars[1][$item]))
        $vars[0][$item] = $vars[1][$item];
}

$result = array();
array_walk($fields, 'array_walk_filter_by_key', array(&$result, &$array));

LIST / EACH:0.12456 sec

$result = array();
reset($fields);
while (list($key, $value) = each($fields))
{
    if (isset($array[$value]))
        $result[$value] = $array[$value];
}

ARRAY_INTERSECT_KEY:0.27264秒(订单不正确)

$result = array_intersect_key($array, array_flip($fields));

ARRAY_REPLACE(array_intersect_key秒):0.29409秒(意外结果:附加值)

$result = array_replace(
    array_fill_keys($fields, false),
    array_intersect_key($array, array_flip($fields))
);

ARRAY_REPLACE(两个array_intersect_key):0.33311秒

$flip = array_flip($fields);
$result = array_replace(
    array_intersect_key($flip, $array),
    array_intersect_key($array, $flip)
);

ARRAY_WALK(设置为空):3.35929秒(意外结果:其他值)

function array_walk_filter_by_key_null(&$item, $key, $array)
{
    if (isset($array[$key]))
        $item = $array[$key];
    else
        $item = null;
}

$result = array_flip($fields);
array_walk($result, 'array_walk_filter_by_key_null', $array);

ARRAY_REPLACE(array_intersect_key first):11.11044 sec

$flip = array_flip($fields);
$result = array_intersect_key(
    array_replace($flip, $array),
    array_intersect_key($flip, $array)
);

ARRAY_MERGE:14.11296秒(意外结果:其他值)

$result = array_splice(
    array_merge(array_flip($fields), $array),
    0,
    count($fields)
);

就是这样。 DIY不能打败。有时人们认为内置函数更快,但情况并非总是如此。编程器现在相当不错。

答案 3 :(得分:1)

我相信这可以按照您的要求运作。

$result = array_splice(array_merge(array_flip($fields) , $array) , 0 , count($fields));

答案 4 :(得分:1)

只是为了解决难题:

$result = array_replace(
  array_intersect_key(array_flip($fields), $array),
  array_intersect_key($array, array_flip($fields))
);

第一个array_intersect以良好的顺序创建字段列表,另一个使用array_replace功能来创建第一个数组中不存在的键。

满足您的要求。但我不会在任何生产代码中使用它,因为这可能相当沉重(虽然我没有基准测试,所以这只是一种直觉)。 array_walk解决方案似乎更轻松。

答案 5 :(得分:1)

此代码保留顺序并根据需要在PHP 5.2中运行

一行:

$result = array_merge( array_flip($fields),
                       array_intersect_key(
                                          $array,
                                          array_flip( $fields )
                                          )
                       );

表现:

$flip = array_flip($fields);
$result = array_merge( $flip
                       array_intersect_key(
                                          $array,
                                          $flip
                                          )
                       );

答案 6 :(得分:0)

如果您想保留$fields的密钥订单,可以尝试:(如果$array中不存在密钥,则该密钥的值将为空。)

$result = array_flip($fields);
array_walk($result, function(&$item, $key, $array) {
  $item = isset($array[$key]) ? $array[$key] : null;
}, $array);

var_dump($result);

答案 7 :(得分:0)

我会考虑你不能改变输入($ array或$ fields)。

如果您的数组使用$ fields中的值作为键,则可以实现此目的。之后,您可以合并两个(将$ fields作为第一个参数)并删除多余的元素。

考虑到您无法更改$ fields,我将创建它:

$tmp = array_combine($fields, range(1, count($fields)));
$result = array_merge($tmp, $array);
$result = array_splice($result, 0, count($fields));

可以在此处找到完整的工作样本(带有一些注释):http://codepad.org/H0CDN7ok

答案 8 :(得分:0)

我的尝试:

    array_replace(
            array_fill_keys($fields, false),
            array_intersect_key($array,             # Keys in array, without order
                    array_flip($fields))));

按照与$ array相同的顺序获取密钥很容易。然后为了让它们按正确顺序排列,我构建了一个数组,其中的键等于$ fields。 Array_replace完成了其余的工作。

解决方案是“稳定的”,因为$ array中缺少的键将被替换为FALSE,因此可以在需要时被过滤掉。

array_flip遍历大小为N的字段数组,array_intersect遍历N个大小的数组,array_fill_keys为N,最后的array_replace是,我相信N ^ 2.

所以总费用是M * N ^ 5.

走最小的数组并从大数组中选取值是O(M ^ 2 * N ^ 2),因此对于大的N值,我怀疑PHP解决方案可能证明更快。这不会输入不在数据数组中的键。

   $answer = array();
   foreach($fields as $fld)     // N-sized cycle
       if (isset($array[$fld])) // Cost M
           $answer[$fld] =      // Assignment is N*1/2
               $array[$fld];    // Getting value is another M

(稍后会有一些困惑)

我跑了一张支票,我想我一定是犯了一些愚蠢的错误,因为我得到的时间完全是荒谬的。不可否认,我使用的是一个非常短的$ fields数组,所以我预计结果会有偏差,但不会这个偏斜。除非使用一些非常聪明的哈希技巧计算$ answer [$ fld],否则解释解的真实成本不是O(M ^ 2 * N ^ 2),而是O(K * N ^ 2),其中K小。< / p>

如果有人想和我一起玩或告诉我我可能犯了什么愚蠢的错误,这就是基准。

关于发布这个问题,我有两种想法,因为另一个明显的解释是,我在某个地方犯了一个荒谬,愚蠢的错误,我最终会在我脸上染上鸡蛋,但是,哦,到底是怎么回事。 / p>

    $array = array(
        'random' => 1,
        'pewpew' => 2,
        'temp' => 5,
        'xoxo' => 3,
        'qweqweqe' => 4,
    );
    $fields = array('random', 'xoxo', 'temp');
    // Let's not print anything just yet, maybe that's what screwing the timer?
    $results = '';
    $duh = 0;

    for ($cycle = 0; $cycle < 10; $cycle++)
    {
            // Add some more elements to $array.
            for ($i = 0; $i < 10000; $i++)
            {
                    $k = uniqid();
                    $array[$k] = 42;
            }
            $start  = explode(' ', microtime());
            // WTF? Do more cycles to average the timing.
            for ($j = 0; $j < 10; $j++)
            {
                    // 0 or 1 to switch
                    if (1)
                    {
                    // INTERPRETED ANSWER
                    $answer = array();
                    foreach($fields as $fld)     // N-sized cycle
                       if (isset($array[$fld])) // Cost M
                           $answer[$fld] =      // Assignment is N*1/2
                               $array[$fld];    // Getting value is another M
                    } else {
                    // FUNCTION ANSWER
                    $answer = array_replace(
                            array_fill_keys($fields, false),
                            // array_combine($fields, $fields),
                            array_intersect_key($array,             # Keys in array, without order
                                    array_flip($fields)));
                    }
                    // USE $answer so to avoid premature optimization?
                    // You can't be that clever.
                    $duh += strlen(serialize($answer));
            }
            $stop   = explode(' ', microtime());
            // An error in timing? Check via a stupid roundabout.
            $int    = $stop[1]-$start[1]+1;
            $int    += ($stop[0]-$start[0]);
            $int    -= 1;
            $elapsed = number_format($int * 1000000, 2);
            $results        .= "".(5000*$cycle)." = $elapsed us.\n";
    }

    // I need to get in result:
    $wanted = array(
        'random' => 1,
        'xoxo' => 3,
        'temp' => 5,
    );
    // DID we get the right answer?
    print "Wanted:\n"; print_r($wanted);
    print "Gotten:\n"; print_r($answer);
    print "Results: $results\n$duh -- count of array is " . count($array);

    // And yet I have always the same realtime, name of a dog, how can that be?
    // I must be doing something REALLY REALLY wrong somewhere.

答案 9 :(得分:0)

此解决方案还处理$fields中某些$array不作为键出现的情况:

$flip = array_flip($fields);
$result = array_intersect_key(array_replace($flip, $array), array_intersect_key($flip, $array));

如果已知$fields中的所有$array都作为$flip = array_flip($fields); $result = array_intersect_key(array_replace($flip, $array), $flip); 中的键出现,则可以使用这个更简单的解决方案:

$result = array_intersect_key(array_replace($flip=array_flip($fields), $array), $flip);

可以写成这样的单行:

$fields

如果某些$array不是$array的键,但0包含计数,那么返回错误键的flip()计数是有意义的,我们可以替换array_fill_keys($fields, 0)$result = array_intersect_key(array_replace($fill=array_fill_keys($fields, 0), $array), $fill);

array_filter()

如果需要,我们可以应用0再次过滤掉0。通过将false替换为null$array,当值不是计数时,我们可以标记并处理$array中缺少密钥。

令人遗憾的是,这些解决方案与此页面上的所有其他解决方案一样,必须处理$fields的所有键,而任何显式循环都在count($array)上。目前看来,当count($fields)远大于array_walk()时,没有基于数组函数的解决方案和显式循环一样快(因为它们会在回调函数中显式构造结果,我认为array_reduce()array_在这里是显式循环。

问题在于,没有任何可用的$fields函数会破坏键和值之间的关联,因为我们想循环$array,或者更确切地说是一个翻转的数组,也是为了保存它排序顺序,同时保持{{1}}的值,我们运气不好。

答案 10 :(得分:0)

PHP函数名为array_diff_key

示例代码:

$array = array(
    'random' => 1,
    'pewpew' => 2,
    'temp' => 5,
    'xoxo' => 3,
    'qweqweqe' => 4
);

$fields = array('random', 'xoxo', 'temp');
$result = array_diff_key($fields, $array);

这将产生所需的结果。

演示:http://shaquin.tk/experiments/array1.php

编辑:如果$fields可以包含$array中不是键的值,请使用以下代码:

$result = array_diff_key($fields, $array);
$result = array_intersect_key(array_flip($fields), $array);
$result = array_flip(array_diff(array_keys($result), $array));
$result = array_replace($result, $array);
$result = array_flip(array_intersect(array_flip($result), $fields));

有可能对此进行优化,但它有效!

注意:我无法链接到示例,因为我的(托管)网站没有&gt; = PHP 5.3,但是,我可以链接到类似的:http://shaquin.tk/experiments/array2.php

答案 11 :(得分:0)

简单方法:

$array = array(
   'random' => 1,
        'pewpew' => 2,
        'temp' => 5,
        'xoxo' => 3,
        'qweqweqe' => 4,
);

$fields = array('random', 'xoxo', 'temp');

$output = array();

foreach ($fields as $value) 
    if(isset($array[$value]))
         $output[$value]=$array[$value];            

答案 12 :(得分:-1)

尝试:

$result=array();
reset($fields);
while(list($key,$value)=each($fields))
{
    if(isset($array[$value])) $result[$value]=$array[$value];
}

答案 13 :(得分:-1)

这将有效并保留您的订单:

$fields = array_flip($fields);
array_merge($fields,array_intersect_key($array, $fields));
$fields = array_keys($fields);

注意,你可以两次调用array_flip,但上面看起来有点“干净”。