2

キー「menu_title」と「id」を持つ配列の2つの配列があります。

2つの配列を調べて、「menu_title」を2番目の配列の配列と共有する最初の配列の任意の配列のIDを3番目の配列に格納したいと思います。

私はそのようにそれを行うことができることを知っています:

$collision = [];
foreach($children as $child)
    foreach($siblings as $sibling)
        if($child['menu_title'] == $sibling['menu_title'])
            $collision[] = $child['id'];

しかし、それは私が最初のすべてのアイテムの2番目の配列をループしていることを意味します。

おそらくこれはより良いでしょうか?

$collision = [];
foreach($siblings as &$sibling)
        $sibling = $sibling['menu_title'];

    foreach($children as $child)
        if(in_array($child['menu_title'], $siblings))
            $collision[] = $child['id'];

しかし、私はまだもっと良い方法があるに違いないと思いますか?


アップデート

配列にはsqlが入力されます。基本的に、カテゴリを削除すると、削除するカテゴリと同じレベルに子カテゴリが移動します。

しかし、子のいずれかが削除カテゴリの兄弟の1つと同じmenu_titleを持っている場合は、子のmenu_titleの名前を「whatever-1」(例:「computers-1」)に変更する必要があります。

だから私は更新する必要のあるIDの配列を構築していて、それからそれらのIDに対してsql更新を行います。おそらくこれにアプローチする方法に拡張が行われる可能性がありますか?


アップデート

だから、結局私は次のようになりました:

$id = 4;
$category = $this->categoryeditormodel->getCategory($id);
$children = $this->categoryeditormodel->getChildCategories($id);
$siblings = $this->categoryeditormodel->getSiblingCategories($id);

foreach($siblings as &$sibling)
    $sibling = $sibling['menu_title'];

foreach($children as &$child){
    $child['parent_id'] = $category['parent_id'];
    if(in_array($child['menu_title'], $siblings)){
        $i = 0;
        while(in_array(($name = ($child['menu_title'].'-'.++$i)), $siblings));
        $child['menu_title'] = $name;
    }
}
$this->categoryeditormodel->update_batch($children);

上部の3つの関数は、それらが言うことを実行しますが、カテゴリがすでにキャッシュにロードされているため、別のSQLクエリではないため安価です。

update_batchは、Code Igniters update_batch関数への単なるショートカットですが、テーブル名とidキーを通過します。

何かご意見は?

4

4 に答える 4

2

本質的に、これはO(m * n)です。ここで、mとnは2つの配列のサイズです。したがって、これ以上のことはできません。最後に、各(兄弟、子)ペアを確認する必要があります。これらの配列がどのように配置されるかについてより具体的にできない限り、改善の余地はあまりありません。

これを最適化するための微調整があるかもしれませんが、すぐには何も起こりません。おそらく、劇的な違いをもたらすものは何もありません。

編集:最初にO(n * log n + m * log m)である両方の配列を並べ替えると、実際に配列にあるものに応じて、漸近的に改善できる可能性があります。配列がかなり大きくない限り、これはおそらく役に立ちません。

于 2012-08-22T10:33:39.743 に答える
1

これはSQLで直接行うことができます。

カテゴリテーブルは次のようなものだと思います(元の階層を示すためにタイトルをインデントしました):

id    parent title
1     0      computers
2     1         laptop
3     1         desktop
4     1         *servers*     <--
5     0      *servers*        <--
6     0      printers

そして、私がDEL_IDと呼ぶID1の「コンピューター」を削除したいとします。これを行うには:

  • 行DEL_ID、特に親カテゴリIDPAR_IDに関する情報を取得します
  • 親がDEL_IDであるすべての行を更新して、親がPAR_IDになるようにします
  • IDがDEL_IDの行を削除します。

これを行うときは、DEL_IDの親を持つ行が、親PAR_IDを持つ行と同じタイトルを持っていないことを確認する必要があります。彼らがそうするとき、あなたは彼らの名前を更新します。

したがって、SQLでは:

UPDATE table SET title = CONCAT(title, '-1') FROM table
    JOIN table AS check ON (
        table.parent = DEL_ID
        AND check.parent = PAR_ID
        AND table.title = check.title);

UPDATE table SET parent = PAR_ID WHERE parent = DEL_ID;
DELETE FROM table WHERE id = DEL_ID;

問題は、何らかの理由で、victimCategoryの兄弟の中に「title」と「title-1」がすでにあり、その子の1つが再び「title」である場合に発生する可能性があります。その場合、「title」の名前を「title-1」に変更すると、競合が発生します(PHPの実装で発生したのと同じ問題)。

この状況を検出するには、最初のUPDATEをSELECTに変換し、カテゴリの「古い」タイトルと「提案された」タイトルを取得してから、新しいSELECTを実行して、「提案された」名前を受け入れた場合に重複がないことを確認します。チェック選択が競合する行を返さなくなるまで、-1、-2などのサフィックスをインクリメントします。またはLIKE、古い「title%」のすべてのタイトルを一挙に取得し、存在する場合(競合が発生することを意味します)、辞書式ではなく数値的に大きいものを選択します。つまり、title-11は>title-2です。 -、その数を1つ増やし、それを新しい更新に使用します。これは、1つずつ実行する必要があります。/ is /高価ですが、めったに起こらないと思います。

于 2012-08-22T10:54:14.677 に答える
0

これを行うためのより良い方法はないと思います。2つのアレイを比較する場合は、ループでそれらをウォークオーバーする必要があります。データベースのようにインデックスを作成できますが、配列に1000を超えるものが含まれていない場合はどうでしょうか。それだけの価値のない要素。

とにかく、インデックスを作成するには:

$index = array();
foreach($siblings as $sibling)
{
  $index[$sibling['menu_title']] = true;
}
foreach($children as $child)
{
  if (isset($index[$child['menu_title']])) $collision[] = $child['id'];
}
于 2012-08-22T10:34:23.857 に答える
0
$collision = array_intersect($children, $siblings);

これで、値が繰り返される配列が得られるはずです。array_intersectを確認してください

于 2012-08-22T10:37:14.577 に答える