4

私は仲間を助けようとしていて、彼女はアレイに固執しているので、今回はデータベースを使用しません:(郡のページにはすべての郡が表示され、クリックすると、その郡の散歩を表示する別のページに移動します.

$countys = array();
$countys[101] = array(
                "name" => "Armagh",
                "img" => "css/images/map.jpg",
                "largeimg" => "css/images/banmap.jpg"
            );

$countys[102] = array(
                "name" => "Antrim",
                "img" => "css/images/map.jpg",
                "largeimg" => "css/images/banmap.jpg"
            );

$walks = array();
$walks[1] = array(
    "name" => "Portadown Walk",
    "county" => "Armagh",
    "img" => "css/images/map.jpg",
    "location" => "Portadown", 
    "largeimg" => "css/images/banmap.jpg"
);

$walks[2] = array(
    "name" => "Antrim Walk",
    "county" => "Antrim",
    "img" => "css/images/map.jpg",
    "location" => "Causeway"
);

$walk['county'] が郡と等しいかどうかを確認するために、多次元配列は問題なく機能するでしょうか、それとも for/while ループでしょうか?

4

3 に答える 3

15

テーブル

配列をデータベースとして使用する場合、テーブルをモデル化する最良の方法は 2D 配列を使用することです。

$counties = array();
$countiesKey = 0;

// add a row
$counties[++$countiesKey] = array(
    "name"     => "Armagh",
    "img"      => "css/images/map.jpg",
    "largeimg" => "css/images/banmap.jpg"
);
// and another...
$counties[++$countiesKey] = array(
    "name"     => "Antrim",
    "img"      => "css/images/map.jpg",
    "largeimg" => "css/images/banmap.jpg"
);

これは、次のテーブル定義とほぼ同じです (簡単にするために、比較に MySQL を使用し、すべての文字列フィールドが であると仮定しますVARCHAR(1024))。

CREATE TABLE counties (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(1024),
    img VARCHAR(1024),
    largeimg VARCHAR(1024)
);

一意のインデックス

したがって、配列インデックスを主キーとして使用しています。ただし、主キー以外の「列」に基づいてデータベースを検索するには、O(n)操作が必要です。テーブル全体を繰り返し処理し、すべての行の関連値を検査する必要があります。ここでインデックスの出番です。郡名にもインデックスを追加したい場合はどうすればよいでしょうか? 別の連想配列を使用できます。

$countiesNameIndex = array();
$countiesNameIndex['Armagh'] = 1;
$countiesNameIndex['Antrim'] = 2;

連想配列はハッシュ テーブルとして実装されるため、キーによる要素へのアクセスは大まかにO(1). これにより、郡名で検索するときに行へのアクセスを大幅に高速化できます。

$search = 'Antrim';
$result = array();
if (isset($countiesNameIndex[$search])) {
    $result[$countiesNameIndex[$search]] = $counties[$countiesNameIndex[$search]];
}
return $result;

このインデックスは、行が追加および削除されるときに動的に維持できます。

// Insert a row
$row = array( /* row data */ );
if (isset($countiesNameIndex[$row['name']])) {
    // insert fails, duplicate value in column with unique index
}
$counties[++$countiesKey] = $row;
$countiesNameIndex[$row['name']] = $countiesKey;

// Delete a row
$idOfRowToDelete = 2;
if (isset($counties[$idOfRowToDelete])) {
    unset(
        $countiesNameIndex[$counties[$idOfRowToDelete]['name']], 
        $counties[$idOfRowToDelete]
    );
}

このインデックス作成アプローチにより、データ セットが大きくなるにつれて、データ アクセスが大幅に高速化されます。


非クラスター化インデックス

参照する行の順序に関する情報を持たない一意でないインデックスを実装する方法を簡単に見てみましょう。実装は非常に似ています。これは、一意のインデックスよりも少し遅くなりますが、データセット全体を反復するよりも著しく高速です。

$countiesImgIndex = array();

// Insert a row
// INSERT INTO counties ( ... ) VALUES ( ... )
$row = array( /* row data */ );
if (!isset($countiesImgIndex[$row['img']])) {
    $countiesImgIndex[$row['img']] = array();
}
$counties[++$countiesKey] = $row;
$countiesImgIndex[$row['img']][] = $countiesKey;

// Search using the index
// SELECT * FROM counties WHERE img = 'css/images/map.jpg'
$search = 'css/images/map.jpg';
$result = array();
if (isset($countiesImgIndex[$search])) {
    foreach ($countiesImgIndex[$search] as $rowId) {
        $result[$rowId] = $counties[$rowId];
    }
}
return $result;

// Delete a row
// DELETE FROM counties WHERE id = 2
$idOfRowToDelete = 2;
if (isset($counties[$idOfRowToDelete])) {
    $key = array_search($idOfRowToDelete, $countiesImgIndex[$counties[$idOfRowToDelete]['img']]);
    if ($key !== false) {
        array_splice($countiesImgIndex[$counties[$idOfRowToDelete]['img']], $key, 1);
    }
    unset($counties[$idOfRowToDelete]);
}

複数のインデックスの使用

これらのインデックスを使用して、より複雑な操作を実行することもできます - SQL クエリの実装方法を検討してください

SELECT *
FROM counties
WHERE name = 'Antrim'
  AND img  = 'css/images/map.jpg'

まず、最も具体的なインデックス (一意のインデックス) を確認します。

$result = array();

$nameSearch = 'Antrim';
$imgSearch = 'css/images/map.jpg';

if (!isset($countiesNameIndex[$nameSearch])) {
    return $result;
}

次に、その行が他の条件に一致するかどうかを確認します。

if ($counties[$countiesNameIndex[$nameSearch]]['img'] === $imgSearch) {
    $result[$countiesNameIndex[$nameSearch]]
        = $counties[$countiesNameIndex[$nameSearch]];
}

return $result;

この場合、クエリ対象の列の 1 つに一意のインデックスがあるため、1 つのインデックスのみを使用する必要があることがわかります。これは、重要な唯一の行に直接移動して、条件に一致することを確認できることを意味します。ここで、別の一意でない列にインデックスがあると想像してみましょう - largeImg。この操作はもう少し複雑ですが、次を使用してショートカットを作成できますarray_intersect()

$result = array();

$imgSearch = 'css/images/map.jpg';
$largeImgSearch = 'css/images/banmap.jpg';

if (!isset($countiesImgIndex[$imgSearch], $countiesLargeImgIndex[$largeImgSearch])) {
    return $result;
}

return array_intersect(
    $counties[$countiesImgIndex[$imgSearch]], 
    $counties[$countiesLargeImgIndex[$largeImgSearch]]
);

外部キーと結合テーブル

しかし、別のテーブルと結合したい場合はどうでしょうか? 繰り返しますが、これは SQL で行う場合とよく似ています。次の SQL テーブル定義があるとします。

CREATE TABLE walks (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(1024),
    location VARCHAR(1024),
    county INT
);

明らかに、別の配列から始めて、いくつかの行を挿入します。

$walks = array();
$walksKey = 0;

$walks[++$walksKey] = array(
    "name" => "Portadown Walk",
    "county" => 1,
    "location" => "Portadown", 
);
$walks[++$walksKey] = array(
    "name" => "Antrim Walk",
    "county" => 2,
    "location" => "Causeway"
);

何が起こっているかは明らかcountyで、列は$countiesテーブル内の行の ID を参照しています。ちなみに、代入構文を使用する代わりにカウンターを使用して ID を追跡する理由$arr[] =は 2 つあります。1 つ目は、テーブルから行が削除されたときに ID が常に一定であることを保証することです。 ) 最後に挿入された行の ID を抽出します。これは、ここに示すように、外部キーを使用して複雑なテーブル構造を作成するときに役立ちます。

それでは、このデータを関連付けてみましょう。次の SQL クエリを実行したとします。

SELECT c.*, w.*
FROM walks w
JOIN counties c ON w.county = c.id
LIMIT 0, 10

これは次のように実装できます。

$result = array();
$i = 0;
foreach ($walks as $walkId => $walksRow) {
    $result[$walkId] = array_merge($counties[$walksRow['county']], $walksRow);
    if (++$i == 10) {
        break;
    }
}
return $result;

これで問題を発見したかもしれません: 両方のテーブルに name という列が含まれています。上記のコードは、各行nameのテーブルからの値を返します。walksこの動作は簡単に調整できますが、正確にどのように実装するかは、目的の結果によって異なります。


結果セットの順序付け

PHP は、ここでほとんどの作業を行う関数を提供します - array_multisort(). 注意すべき最も重要な点は、必要な操作の数を最小限に抑えるために、結果行を抽出した後に順序を適用する必要があるということです。

SELECT c.*, w.*
FROM walks w
JOIN counties c ON w.county = c.id
ORDER BY w.location ASC
// Collect the result set in $result as above

$location = array();

foreach ($result as $row) {
    $location[] = $row['name'];
}
array_multisort($location, SORT_ASC, $result);

return $result;

うまくいけば、上記の例は、PHP 配列を使用して RDBMS にいくつかの機能を実装するために使用できるロジックの一部を示し始めているはずです。データセットが大きくなっても、これらの操作を比較的安価に保つ、かなり単純な最適化を行うことができます。

于 2013-04-08T22:53:03.917 に答える