PHP多次元配列検索(特定の値でキーを検索)


114

この多次元配列があります。検索して、「スラッグ」の値に一致するキーのみを返す必要があります。多次元配列の検索に関して他のスレッドがあることは知っていますが、自分の状況に当てはまるほど十分に理解していません。助けてくれてありがとう!

だから私は次のような関数が必要です:

myfunction($products,'breville-one-touch-tea-maker-BTM800XL');
// returns 1

これが配列です:

$products = array (
1  => array(
        'name'          => 'The Breville One-Touch Tea Maker',
        'slug'          => 'breville-one-touch-tea-maker-BTM800XL',
        'shortname'     => 'The One-Touch Tea Maker',
        'listprice'     => '299.99',
        'price'         => '249.99',
        'rating'        => '9.5',
        'reviews'       => '81',
        'buyurl'        => 'http://www.amazon.com/The-Breville-One-Touch-Tea-Maker/dp/B003LNOPSG',
        'videoref1'     => 'xNb-FOTJY1c',
        'videoref2'     => 'WAyk-O2B6F8',
        'image'         => '812BpgHhjBML.jpg',
        'related1'      => '2',
        'related2'      => '3',
        'related3'      => '4',
        'bestbuy'       => '1',
        'quote'         => '',
        'quoteautor'    => 'K. Martino',
        ),

2  => array(
        'name'          => 'Breville Variable-Temperature Kettle BKE820XL',
        'slug'          => 'breville-variable-temperature-kettle-BKE820XL',
        'shortname'     => 'Variable Temperature Kettle',
        'listprice'     => '199.99',
        'price'         => '129.99',
        'rating'        => '9',
        'reviews'       => '78',
        'buyurl'        => 'http://www.amazon.com/Breville-BKE820XL-Variable-Temperature-1-8-Liter-Kettle/dp/B001DYERBK',
        'videoref1'     => 'oyZWBD83xeE',
        'image'         => '41y2B8jSKmwL.jpg',
        'related1'      => '3',
        'related2'      => '4',
        'related3'      => '5',
        'bestbuy'       => '1',
        'quote'         => '',
        'quoteautor'    => '',
        ),
);

回答:


157

非常にシンプル:

function myfunction($products, $field, $value)
{
   foreach($products as $key => $product)
   {
      if ( $product[$field] === $value )
         return $key;
   }
   return false;
}

6
条件付きステートメントでこの関数を使用している場合、返されるキーのインデックスが[0]になることがあるため、型に対して絶対チェックを実行する必要があります。:条件付きのチェックを行っている場合、それは次のようになりますので if (myfunction($array, 'field', 'value') !== FALSE )) // do something...
アンディ・クック

159

別の可能な解決策はarray_search()機能に基づいています。PHP 5.5.0以降を使用する必要があります

$userdb=Array
(
(0) => Array
    (
        (uid) => '100',
        (name) => 'Sandra Shush',
        (url) => 'urlof100'
    ),

(1) => Array
    (
        (uid) => '5465',
        (name) => 'Stefanie Mcmohn',
        (pic_square) => 'urlof100'
    ),

(2) => Array
    (
        (uid) => '40489',
        (name) => 'Michael',
        (pic_square) => 'urlof40489'
    )
);

$key = array_search(40489, array_column($userdb, 'uid'));

echo ("The key is: ".$key);
//This will output- The key is: 2

説明

この関数にarray_search()は2つの引数があります。1つ目は、検索する値です。2番目は、関数が検索する場所です。この関数array_column()は、キーがである要素の値を取得します 'uid'

概要

したがって、次のように使用できます。

array_search('breville-one-touch-tea-maker-BTM800XL', array_column($products, 'slug'));

または、必要に応じて:

// define function
function array_search_multidim($array, $column, $key){
    return (array_search($key, array_column($array, $column)));
}

// use it
array_search_multidim($products, 'slug', 'breville-one-touch-tea-maker-BTM800XL');

オリジナルの例(xfoxawyによる)はDOCSにあります。ページ
array_column()


更新

Vaelのコメントが気になるので、私は簡単なテストを行って、使用array_searchする方法と、受け入れられた回答で提案された方法のパフォーマンスを測定しました。

1000個の配列を含む配列を作成しました。構造は次のとおりです(すべてのデータがランダム化されました)。

[
      {
            "_id": "57fe684fb22a07039b3f196c",
            "index": 0,
            "guid": "98dd3515-3f1e-4b89-8bb9-103b0d67e613",
            "isActive": true,
            "balance": "$2,372.04",
            "picture": "http://placehold.it/32x32",
            "age": 21,
            "eyeColor": "blue",
            "name": "Green",
            "company": "MIXERS"
      },...
]

名前フィールドのさまざまな値を検索する検索テストを100回実行し、平均時間をミリ秒で計算しました。ここでは例を見ることができます。

結果として、この回答で提案された方法では値を見つけるために約2E-7が必要でしたが、承認された回答方法では約8E-7が必要でした。

前に言ったように、このサイズの配列を使用するアプリケーションでは、どちらの時間もかなり許容できます。サイズが大きくなる場合、たとえば100万要素とすると、この小さな違いも大きくなります。

アップデートII

array_walk_recursiveここでの答えのいくつかに言及した方法のテストを追加しました。得られた結果は正しいものです。そして、パフォーマンスに焦点を合わせると、テストで調べた他のパフォーマンスよりも少し悪くなります。テストでは、に基づく方法よりも約10倍遅いことがわかりますarray_search。繰り返しますが、これはほとんどのアプリケーションにとってそれほど重要な違いではありません。

アップデートIII

この方法のいくつかの制限を見つけてくれた@mickmackusaに感謝します。

  • このメソッドは、連想キーでは失敗します。
  • このメソッドは、インデックス付きのサブ配列(0から始まり、連続して昇順のキーを持つ)でのみ機能します。

誰かがこれのパフォーマンスを知っていますか?最終的には遅くなり、5.5が必要になるようです。5.4なのでテストできません。
Vael Victus

理解できない人のために:php 7では、forループの方が高速です。そのeval.inの例で5.6に変更すると、array_searchがわずかに速くなりました。
Vael Victus

賢い!私はarray_combine()をarray_column()と一緒に使用して、既知のキーでデータムを取得する別の配列を作成しましたが、これはよりエレガントです。
デビッド

4
サブ配列キーはから始まるため、array_search()with array_column()を使用してもOPのサンプル配列では機能しません1。このメソッドは、連想キーでも失敗します。このメソッドは、インデックス付きのサブ配列(から始まり、0連続して昇順のキーを持つ)でのみ機能します。これは、array_column()が返された配列に新しいインデックスを生成するためです。
mickmackusa

完全に正しい@mickmackusa、私は答えにあなたの知識を加えました。助けてくれてありがとう
イヴァンロドリゲストーレス

14

このクラスメソッドは、複数の条件で配列を検索できます。

class Stdlib_Array
{
    public static function multiSearch(array $array, array $pairs)
    {
        $found = array();
        foreach ($array as $aKey => $aVal) {
            $coincidences = 0;
            foreach ($pairs as $pKey => $pVal) {
                if (array_key_exists($pKey, $aVal) && $aVal[$pKey] == $pVal) {
                    $coincidences++;
                }
            }
            if ($coincidences == count($pairs)) {
                $found[$aKey] = $aVal;
            }
        }

        return $found;
    }    
}

// Example:

$data = array(
    array('foo' => 'test4', 'bar' => 'baz'),
    array('foo' => 'test',  'bar' => 'baz'),
    array('foo' => 'test1', 'bar' => 'baz3'),
    array('foo' => 'test',  'bar' => 'baz'),
    array('foo' => 'test',  'bar' => 'baz4'),
    array('foo' => 'test4', 'bar' => 'baz1'),
    array('foo' => 'test',  'bar' => 'baz1'),
    array('foo' => 'test3', 'bar' => 'baz2'),
    array('foo' => 'test',  'bar' => 'baz'),
    array('foo' => 'test',  'bar' => 'baz'),
    array('foo' => 'test4', 'bar' => 'baz1')
);

$result = Stdlib_Array::multiSearch($data, array('foo' => 'test4', 'bar' => 'baz1'));

var_dump($result);

生成されます:

array(2) {
  [5]=>
  array(2) {
    ["foo"]=>
    string(5) "test4"
    ["bar"]=>
    string(4) "baz1"
  }
  [10]=>
  array(2) {
    ["foo"]=>
    string(5) "test4"
    ["bar"]=>
    string(4) "baz1"
  }
}

こんにちはFatalist stackoverflow.com/questions/40860030/...。これらの質問は終了しました。その質問を明確にしてください
KARTHI SRV '29

4

この関数を使用します。

function searchThroughArray($search,array $lists){
        try{
            foreach ($lists as $key => $value) {
                if(is_array($value)){
                    array_walk_recursive($value, function($v, $k) use($search ,$key,$value,&$val){
                        if(strpos($v, $search) !== false )  $val[$key]=$value;
                    });
            }else{
                    if(strpos($value, $search) !== false )  $val[$key]=$value;
                }

            }
            return $val;

        }catch (Exception $e) {
            return false;
        }
    }

関数を呼び出します。

print_r(searchThroughArray('breville-one-touch-tea-maker-BTM800XL',$products));

素敵な答え。あなたは私の答えであなたの提案のパフォーマンスをチェックすることができます
イヴァン・ロドリゲス・トーレス

StackOverflowでは、コードのみの回答は価値が低いです。投稿を更新して、リーフノードの部分文字列検索機能の仕組みを説明してください。この方法は、OPが要求するように特別に機能するようには設計されていないため、違いを明確にすることが重要です。デモリンクは読者の理解を大幅に改善します。常にOPとSOの対象者を教育する目的で回答を投稿してください。
mickmackusa

1
function search($array, $key, $value) 
{ 
    $results = array(); 

    if (is_array($array)) 
    { 
        if (isset($array[$key]) && $array[$key] == $value) 
            $results[] = $array; 

        foreach ($array as $subarray) 
            $results = array_merge($results, search($subarray, $key, $value)); 
    } 

    return $results; 
} 

StackOverflowでは、コードのみの回答は価値が低いです。投稿を更新して、再帰メソッドがどのように機能するか、それが適切な状況、および再帰が不要なオーバーヘッドである状況を説明してください。OPとより多くのSO視聴者を教育する目的で、常に回答を投稿してください。
mickmackusa

1

次の訪問者のために:再帰的な配列ウォークを使用します。多次元配列内のすべての「リーフ」を訪問します。ここにインスピレーションがあります:

function getMDArrayValueByKey($a, $k) {
    $r = [];
    array_walk_recursive ($a, 
                          function ($item, $key) use ($k, &$r) {if ($key == $k) $r[] = $item;}
                          );
    return $r;
}

問題ない!時間を節約するために、ジョセフの答えを試すと、関数は1つの要素を持つ配列を返します。キーは:)希望答えである
イバン・ロドリゲス・トーレス

@Ivan josefの答えはこれとは大きく異なります。これを自分でテストしましたか。私はこの答えに注目し続けていますが、array_walk_recursiveがレベルを確認できないため、うまくいくとは思いません。第1レベルのキーごとに、josefはstrposを呼び出すか、すべてのリーフノードをチェックしています。違いを見ます?
mickmackusa

もちろん@mickmackusaしかし、Hansはある種のインスピレーションを与えており、答えは文字通りの解決策ではありません。ジョセフが彼の答えでしたように、それはより複雑にする必要があります。しかし、あなたはこの回答が問題を完全に扱っていないという点で正しいです。
イバン・ロドリゲス・トーレス

1

私は以下のようにしたいと思います、ここで$products最初の問題で与えられた実際の配列です。

print_r(
  array_search("breville-variable-temperature-kettle-BKE820XL", 
  array_map(function($product){return $product["slug"];},$products))
);

0

これを試して

function recursive_array_search($needle,$haystack) {
        foreach($haystack as $key=>$value) {
            $current_key=$key;
            if($needle==$value['uid'] OR (is_array($value) && recursive_array_search($needle,$value) !== false)) {
                return $current_key;
            }
        }
        return false;
    }

StackOverflowでは、コードのみの回答は価値が低いです。投稿を更新して、再帰メソッドがどのように機能するか、それが適切な状況、および再帰が不要なオーバーヘッドである状況を説明してください。OPとより多くのSO視聴者を教育する目的で、常に回答を投稿してください。psの私は、ほとんどのPHP開発者がすることを好むだろうと思います&&し、||代わりにANDORあなたの状態に。宣言する理由はありませんcurrent_key。の比較$needleは厳密でなければなりません。
mickmackusa
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.