9

这是数据

$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_ 函数执行此转换吗?(我不想使用iteations)如果是:你能链接我需要的功能吗?

(抱歉拼写错误)

更新。

PHP 5.2

4

14 回答 14

5
$result=array_intersect_key($array ,array_flip($fields) );
于 2012-06-29T16:12:03.240 回答
3
// little trick required here...
$fields = array('random' => 0, 'xoxo' => 0, 'temp' => 0);
$result = array_intersect_key($array,$fields);
于 2012-06-29T16:07:22.947 回答
2

我总是对这些类型的问题感兴趣,它是关于高效代码的(包括代码使用和速度)。也就是说,我尝试了几种不同的方法并对其进行了基准测试,但没有什么比简单的foreach!

我尝试了所有发布的解决方案,以及我自己的 array_walk 和基本的 foreach。我使用 Miraage 发布的数组和字段进行了几次测试,其中一些使用了更大的数组。我还注意到结果有任何奇怪之处,例如如果 $fields 的值不在 $array 中,则附加值。

我已经按速度订购了。

FOREACH: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));

列表/每个:0.12456 秒

$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 sec

$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 优先):11.11044 秒

$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。有时人们认为内置函数更快,但并非总是如此。这些天编译器非常好。

于 2012-07-08T12:37:08.307 回答
1

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

$result = array_splice(array_merge(array_flip($fields) , $array) , 0 , count($fields));
于 2012-07-04T17:19:18.463 回答
1

只是为了解决这个难题:

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

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

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

于 2012-07-04T23:08:38.493 回答
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
                                          )
                       );
于 2012-07-09T10:16:32.383 回答
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);
于 2012-07-03T02:33:59.050 回答
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

于 2012-07-04T12:57:22.270 回答
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 大小的数组 M 次,array_fill_keys 花费 N 并且我相信最终的 array_replace 是 N^2。

所以总成本是 M*N^5。

遍历最小数组并从大数组中选取值是 O(M^2*N^2),因此对于较大的 NI 值,怀疑 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 很小。

如果有人想玩弄时间或告诉我我可能犯了什么愚蠢的错误,这里是基准。

我对发布这个有两种想法,因为另一个明显的解释是我在某个地方犯了一个可笑、愚蠢的错误,我最终会在我的脸上留下鸡蛋,但是,哦,到底是什么。

    $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.
于 2012-07-06T20:28:00.827 回答
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的计数是有意义的,我们可以替换为:0flip()array_fill_keys($fields, 0)

$result = array_intersect_key(array_replace($fill=array_fill_keys($fields, 0), $array), $fill);

如果需要,我们可以应用 an再次array_filter()过滤掉0s 。通过替换0orfalse我们可以在值不计数时null标记和处理缺少键的情况。$array

可悲的是,这些解决方案,就像这个页面上的所有其他解决方案一样,必须通过 的所有键$array,而任何显式循环都将在$fields。目前,似乎 whencount($array)count($fields)没有像显式循环一样快的基于数组函数的解决方案要大得多(因为他们会在回调函数中显式构造结果,我认为array_walk()这里array_reduce()是显式循环)。

问题是没有一个可用的array_函数破坏键和值之间的关联,并且由于我们想要循环$fields,或者更确切地说是一个翻转的数组,也为了保持它的排序顺序,同时保持 的值$array,我们没有运气。

于 2012-07-06T22:22:13.213 回答
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));

可以稍微优化一下,但它有效!

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

于 2012-07-08T11:03:56.507 回答
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];            
于 2012-07-09T11:29:10.920 回答
-1

尝试:

$result=array();
reset($fields);
while(list($key,$value)=each($fields))
{
    if(isset($array[$value])) $result[$value]=$array[$value];
}
于 2012-06-29T16:03:19.187 回答
-1

这将为您工作并保持秩序:

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

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

于 2012-07-03T15:25:56.977 回答