1

私はこれを数回ヒットしましたが、それに取り組むための最良の方法を見つけたことはありません。具体的な例で説明するのが最も簡単です。サンプルデータ:

product_id     display_name         display_order
----------     ------------         -------------
"samgal3"      "Samsung Galaxy 3"        0
"motorazrh"    "Motorola Razr HD"        1
"iphone5"      "Apple iphone 5"          2

etc

実際の配列は、常にではありませんが、多くの場合小さく (<20 項目)、一意のキー/値が保証されています。各アイテムには、一意のソート キー (html テーブル/列挙のリスト順)、一意の内部キー (アイテム ルックアップ用)、および人間が判読できる表示名があります。

通常、オプションのリストがフォームで使用されているときに、この問題が発生します。同じデータが、フォームのドロップダウン ボックスへの入力と、送信された $GET/POST データの検証の両方に使用されます。フォームを生成するときは、SELECT ボックスのオプションを順番に作成するために、「並べ替え」順に列挙/リストする必要があります。フォームが送信されたら、「product_id」で検索できる必要があります (「...&action=view&product_id=elephant...」がリスト内の製品であることを検証するため)。

'sort'=>array(other data) をキーにすると、'sort' で表示するのは簡単ですが、$data[ * ]['product_id'] 内を検索するのは難しい *(つまり、$KEY が存在する場合は特定し、 $data[$KEY]['product_id'] == 'htcvox')* を持っています。'product_id'=>array(other data) をキーとして使用すると、'samgal3' が配列内にあるかどうかを検索し、そのデータを見つけるのは簡単ですが、'sort' によって配列をウォーク/列挙して作成する簡単な方法はありません。形。

$data の任意のメンバー $i の検索/ソート キーが $i['product_id'] または $i['sort'] であるカスタム検索/ソートを行うことができると思いますが、それは不器用で、私はそれをやったことがありません前。コードがオープンソースになるため、シンプルさが重要です。

次のように、データを配列の配列としてコーディングすることを期待しています。

$data = array(
    0 => array('product_id'=>'samgal3',   'display_name' => 'Samsung Galaxy 3'),
    1 => array('product_id'=>'motorazrh', 'display_name' => 'Motorola Razr HD'),
    ...

また

$data = array(
    'samgal3'   => array('sort'=>0, 'display_name' => 'Samsung Galaxy 3'),
    'motorazrh' => array('sort'=>1, 'display_name' => 'Motorola Razr HD'),
    ...

$data = array(array1, array2 , array3, ....); $data = array(array1, array2, array3, ....); array1、array2、array3、... のすべてに固定名のキー/フィールドが含まれている場合、$ARRAY[ * *]['named_field'] でネストされた配列を検索/ソートする簡単な方法はありますか?

4

2 に答える 2

0

必要なのは、リレーショナル データベースの 1 つのテーブルに複数のインデックスを配置するのと同じように、基本的に複数のインデックスを 1 つの配列に配置することです。(並べ替えは別ですが、関連する問題です。)

この基本的なデータ構造、つまりキーに特に重要性がない単純な配列のセットから始めましょう。

$data = array(
    array('display_order'=> 0, 'product_id'=>'samgal3',   'display_name' => 'Samsung Galaxy 3'),
    array('display_order'=> 1, 'product_id'=>'motorazrh', 'display_name' => 'Motorola Razr HD'),
    array('display_order'=> 2, 'product_id'=>'a', 'display_name' => 'a'),
    array('display_order'=> 3, 'product_id'=>'c', 'display_name' => 'c'),
    array('display_order'=> 4, 'product_id'=>'d', 'display_name' => 'd'),
    array('display_order'=> 5, 'product_id'=>'b', 'display_name' => 'b'),
    array('display_order'=> 6, 'product_id'=>'q', 'display_name' => 'q'),
    array('display_order'=> 7, 'product_id'=>'f', 'display_name' => 'f'),
);

明示的なインデックスを簡単に作成し、それを使用して$dataアイテムを取得できます。

$product_id_idx = array_flip(array_map(function($item){return $item['product_id'];}, $data));
$samgal3_array = $data[$product_id_idx['samgal3']]; // same as $data[0]

並べ替えには、よく忘れられる を使用できますarray_multisort。ドキュメントの例 3 を見てください。秘訣は、ソートする配列を作成し、最後の引数として完全なデータ セットを含めることです。例えば:

array_multisort(array_keys($product_id_idx), SORT_ASC, SORT_STRING, $data);

$dataプロダクトキーでソートされるようになりました。の元の数値配列キー$dataは失われますが、これは$product_id_idxもはや使用できないことを意味します。したがって、インデックスを使い続けたい場合は、データ配列のコピーをソートするのが最善です。

これらの両方のアプローチを単一のクラスに組み合わせて、正気を保つことができます。

class MultiIndex {

    protected $array;
    protected $indexes = array();
    protected $indexdefs = array();

    function __construct($array, $indexdefs)
    {
        $this->array = $array;
        $this->indexdefs = $indexdefs;
        foreach ($indexdefs as $name => $column) {
            $this->indexes[$name] = $this->makeIndex($column);
        }
    }

    function makeIndex($column)
    {
        $index = array();
        foreach ($this->array as $k => $v) {
            $index[$v[$column]] = $k;
        }
        return $index;
    }

    function get($key, $index=null)
    {
        $datapk = ($index===null) ? $key : $this->indexes[$index][$key];
        return $this->array[$datapk];
    }

    function getIndex($index)
    {
        return $this->indexes[$index];
    }

    function getData()
    {
        return $this->array;
    }
    function indexedBy($index)
    {
        $indexed = array();
        $indexedcolumn = $this->indexdef[$index];
        foreach ($this->indexes[$index] as $indexk => $arrayk) {
            $newarray = $this->array[$arrayk];
            unset($newarray[$indexedcolumn]);
            $indexed[$indexk] = $newarray;
        }
        return $indexed;
    }

    function sortedBy(/*multisort args*/)
    /* with strings converted to arrays corresponding to index of same name */
    {
        $args = func_get_args();
        foreach ($args as $n => $arg) {
            if (is_string($arg)) {
                $args[$n] = array_keys($this->indexes[$arg]);
            }
        }
        $sorted = $this->array;
        $args[] = $sorted;
        call_user_func_array('array_multisort', $args);
        return $sorted;
    }
}

使用例:

$dataidx = new MultiIndex($data, array('id'=>'product_id', 'disp'=>'display_order'));
var_export($dataidx->sortedBy('disp', SORT_STRING, SORT_ASC));
var_export($dataidx->indexedBy('id'));
var_export($dataidx->get('samgal3', 'id'));

これは、構築するための非常に基本的なベースであり、小さな配列には問題ありません。簡単にするためMultiIndexに、 のデータは不変であり、キーは常に配列インデックスです。これを強化するいくつかの明白な方法は次のとおりです。

  1. $indexdefs配列キーに名前を付けるだけの文字列/int ではなく、項目のキーを返す callable を accept にします。これにより、任意の形状のデータにインデックスを作成したり、データに直接対応しないインデックスを作成したりすることができます。(たとえば、表示名の文字数によるインデックス、または日付と時刻を別々に保持する配列の日付と時刻によるインデックスなど)
  2. インデックス キーが 1 つの値のみを持つという要件を削除します。(現在、作成するすべてのインデックスは一意であると想定されています。)
  3. インデックスのデータ型を宣言し、inSORT_*への引数に自動的に含めることができます。array_multisortMultiIndex::sortedBy()
  4. まばらなインデックスを含める: 非常に一般的または非常にまれな値がある場合、または非常に大きなデータセットがあり、メモリを節約したい場合は、特定の値のみがインデックス付けされるようにすることができます。アイテムがインデックスに見つからない場合は、データ内のインデックスが作成されていないアイテムのフル スキャンにフォールバックします。
  5. 適切なインターフェースの実装を追加します。
  6. に複数のバックエンドMultiIndexを持たせることができるため、配列のような構造 (dbm キー値ストア、DynamoDB のようなクラウド ストア、memcached など) に複数のインデックスを持ち、それらすべてを同じオブジェクト インターフェイスで操作できます。
  7. 変更可能なデータをMultiIndex保持し、データの変更に応じて増分的かつ自動的にインデックスを更新します。

簡単にフォークできるように、このコードを Gist に保持します

于 2013-04-04T01:37:57.480 に答える
0

http://www.php.net/usortを使用して、カスタム ユーザー定義の並べ替えを生成します。

例:

<?php
//added a few more values
$data = array(
    0 => array('product_id'=>'samgal3',   'display_name' => 'Samsung Galaxy 3'),
    1 => array('product_id'=>'motorazrh', 'display_name' => 'Motorola Razr HD'),
    2 => array('product_id'=>'a', 'display_name' => 'a'),
    3 => array('product_id'=>'c', 'display_name' => 'c'),
    4 => array('product_id'=>'d', 'display_name' => 'd'),
    5 => array('product_id'=>'b', 'display_name' => 'b'),
    6 => array('product_id'=>'q', 'display_name' => 'q'),
    7 => array('product_id'=>'f', 'display_name' => 'f'),
);

function cmp($a,$b){
    return strcasecmp($a['display_name'],$b['display_name']);
}

usort($data,'cmp');
var_export($data);

http://codepad.viper-7.com/3mY8nU

于 2013-04-03T23:36:56.827 に答える