【问题标题】:filter array by values in a second array按第二个数组中的值过滤数组
【发布时间】:2017-11-27 03:16:56
【问题描述】:

** 我已经编辑了这个以展示我如何使用 array_search 让我的代码工作

我有一个数组,$arr1,有 5 列:

 key    id  name    style   age whim
 0      14  bob     big     33  no
 1      72  jill    big     22  yes
 2      39  sue     yes     111 yes
 3      994 lucy    small   23  no
 4      15  sis     med     24  no
 5      16  maj     med     87  yes
 6      879 Ike     larg    56  no
 7      286 Jed     big     23  yes

此数组位于缓存中,而不是数据库中。

然后我有一个带有 id 值列表的第二个数组 -

$arr2 = (0=>14, 1=>72, 2=>8790)

如何过滤$arr1,使其仅返回具有$arr2 中id 值的行?

我的代码如下所示:

$arr1 = new CachedStuff();  // get cache

$resultingArray = [];  // create an empty array to hold rows
$filter_function = function ($row) use ($arr2) {
    return (array_search($row['id'], $arr2));
};
$resultingArrayIDs = $arr1->GetIds($filter_function, $resultingArray);

这给了我两个输出:$resultingArray 和 $resultingArrayIDs,它们都代表 $arr1 和 $arr2 的交集。

【问题讨论】:

    标签: php arrays filter array-filter


    【解决方案1】:

    对第二个/过滤数组使用迭代检查的问题在于,随着数组大小的增加,它会降低效率。

    通过将新键分配给第一个数组,并将过滤数组的值翻转到键,您可以对数组运行一次​​过滤/相交,然后重新索引输出数组。

    我的方法没有调用foreach() 循环并且没有迭代条件。

    代码:(Demo)

    $arr1=[
        ['key'=>0,'id'=>14,'name'=>'bob','style'=>'big','age'=>33,'whim'=>'no'],
        ['key'=>1,'id'=>72,'name'=>'jill','style'=>'big','age'=>22,'whim'=>'yes'],
        ['key'=>2,'id'=>39,'name'=>'sue','style'=>'yes','age'=>111,'whim'=>'yes'],
        ['key'=>3,'id'=>994,'name'=>'lucy','style'=>'small','age'=>23,'whim'=>'no'],
        ['key'=>4,'id'=>15,'name'=>'sis','style'=>'med','age'=>24,'whim'=>'no'],
        ['key'=>5,'id'=>16,'name'=>'maj','style'=>'med','age'=>87,'whim'=>'yes'],
        ['key'=>6,'id'=>879,'name'=>'Ike','style'=>'larg','age'=>56,'whim'=>'no'],
        ['key'=>7,'id'=>286,'name'=>'Jed','style'=>'big','age'=>23,'whim'=>'yes']
    ];
    $arr2=[14,72,879];
    
    $arr1=array_column($arr1,null,'id');  // generate temporary keys
    //var_export($arr1);
    
    $arr2=array_flip($arr2);  // move values to keys
    //var_export($arr2);
    
    $filtered=array_intersect_key($arr1,$arr2);  // retain subarrays that qualify
    //var_export($filtered);
    
    $reindexed=array_values($filtered);  // reindex array
    var_export($reindexed);
    

    或像这样写成单行:

    var_export(array_values(array_intersect_key(array_column($arr1,null,'id'),array_flip($arr2))));
    

    输出:

    array (
      0 => 
      array (
        'key' => 0,
        'id' => 14,
        'name' => 'bob',
        'style' => 'big',
        'age' => 33,
        'whim' => 'no',
      ),
      1 => 
      array (
        'key' => 1,
        'id' => 72,
        'name' => 'jill',
        'style' => 'big',
        'age' => 22,
        'whim' => 'yes',
      ),
      2 => 
      array (
        'key' => 6,
        'id' => 879,
        'name' => 'Ike',
        'style' => 'larg',
        'age' => 56,
        'whim' => 'no',
      ),
    )
    

    【讨论】:

    • @ian 我是这个问题的后期发帖人,所以我没有获得任何早期的支持。我想澄清一下,如果我的答案解释得不够好,我的答案是有效的,因为它不会在循环中执行数组扫描。 DecentDabbler 和 Erwin 的解决方案在其循环的每次迭代中执行部分(可能是全阵列扫描),而且成本可能很高。 user2182349 在正确的轨道上,但对临时值而不是临时键执行过滤过程,因此必须调用 foreach() 循环来生成所需的输出数组。
    • 最后一点是,如果您不关心临时密钥,您可以跳过最后一次调用 array_values() 并继续代码中的下一个过程。
    • @ian 和 mickmackusa:是的,这个答案比我的解决方案快得多,尤其是在处理大型缓存集和大型过滤器集时。
    • @mickmackusa 和 Decent Dabbler:谢谢你们。我已经编辑了上面的代码,以展示我如何使用 array_search 来解决我的问题。但是,如果可以应用这种方法来提高效率,我很感兴趣。你们中的任何一个人都可以通过查看我更新的函数来判断吗?
    • @ian 您使用 array_search() 的方式不是“零安全”,因为您的条件是对搜索结果使用松散比较,(真)0 返回值将被错误地评估为假。您需要对false 进行文字/严格检查才能正确使用此函数调用。此外,我再次澄清,使用迭代的array_search()in_array() 方法不如我对两个数组进行单一比较的方法有效。请使用我的方法以获得最佳效率。
    【解决方案2】:

    如果我正确理解了您的问题和数据结构,应该这样做:

    $dataArray = [
      [ 'key' => 0, 'id' => 14  , 'name' => 'bob'  , 'style' => 'big'   , 'age' => 33  , 'whim' => 'no'  ],
      [ 'key' => 1, 'id' => 72  , 'name' => 'jill' , 'style' => 'big'   , 'age' => 22  , 'whim' => 'yes' ],
      [ 'key' => 2, 'id' => 39  , 'name' => 'sue'  , 'style' => 'yes'   , 'age' => 111 , 'whim' => 'yes' ],
      [ 'key' => 3, 'id' => 994 , 'name' => 'lucy' , 'style' => 'small' , 'age' => 23  , 'whim' => 'no'  ],
      [ 'key' => 4, 'id' => 15  , 'name' => 'sis'  , 'style' => 'med'   , 'age' => 24  , 'whim' => 'no'  ],
      [ 'key' => 5, 'id' => 16  , 'name' => 'maj'  , 'style' => 'med'   , 'age' => 87  , 'whim' => 'yes' ],
      [ 'key' => 6, 'id' => 879 , 'name' => 'Ike'  , 'style' => 'larg'  , 'age' => 56  , 'whim' => 'no'  ],
      [ 'key' => 7, 'id' => 286 , 'name' => 'Jed'  , 'style' => 'big'   , 'age' => 23  , 'whim' => 'yes' ]
    ];
    
    $filterArray = [14, 72, 879];
    $resultArray = array_filter( $dataArray, function( $row ) use ( $filterArray ) {
      return in_array( $row[ 'id' ], $filterArray );
    } );
    

    View this example on eval.in


    但是,您的问题似乎表明此数据可能来自数据库;那是对的吗?如果是这样,那么在数据库级别预过滤结果可能更有效。通过在 SELECT 查询中添加一个字段来表示一个布尔值,该值是否与您的过滤器 ID 匹配,或者根本不返回其他行。

    【讨论】:

    • 感谢@Decent Dabbler,它实际上来自缓存。
    【解决方案3】:

    一种方法是使用foreach 循环使用array_search()

    $result = [];
    foreach ($arr1 as $value) {                            // Loop thru $arr1
        if (array_search($value['id'], $arr2) !== false) { // Check if id is in $arr2
            $result[] = $value;                            // Push to result if true
        }
    }
    
    // print result
    print_r($result);
    

    【讨论】:

      【解决方案4】:

      正如@DecentDabbler 提到的 - 如果数据来自数据库,则在 WHERE 上使用 IN 将允许您仅检索相关数据。 p>

      另一种过滤方法是使用数组函数

      • array_columnid 列的值提取到一个数组中
      • array_intersect 返回 $arr1['id'] 和 $arr2 中的元素
      • array_flip 翻转结果数组,使得 $arr1 中的索引指示 $arr1 和 $arr2 中的元素

        $arr1 = [ [ 'id' => 14, 'name' => 'bob'],
                ['id' =>  72, 'name' => 'jill'],
                ['id' =>  39, 'name' => 'sue'],
                ['id' => 994, 'name' => 'lucy'],
                ['id' => 879, 'name'=> 'large']];
        
        $arr2 = [ 14,72,879 ];
        
        $intersection = array_flip(array_intersect(array_column($arr1,'id'),$arr2));
        
        foreach ($intersection as $i) {
                var_dump($arr1[$i]);;
        }
        

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-03-21
        • 2021-03-07
        • 2019-03-01
        • 1970-01-01
        • 1970-01-01
        • 2022-12-18
        • 1970-01-01
        • 2015-02-11
        相关资源
        最近更新 更多