链接两个数组并像MySQL DB一样使用它们

Pie*_*ugh 4 php

我试图帮助一个伙伴和她坚持阵列,所以这次没有数据库使用:( countys页面显示所有的计数,当点击一个时,它被带到显示该县的步行的不同页面.

$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"
);
Run Code Online (Sandbox Code Playgroud)

多维数组是否正常工作或者可能是for/while循环来检查$ walk ['county']是否等于该县?

Dav*_*dom 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"
);
Run Code Online (Sandbox Code Playgroud)

这大致相当于下面的表定义(为了简单起见,我们将使用MySQL进行比较并假设所有字符串字段都是VARCHAR(1024)):

CREATE TABLE counties (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(1024),
    img VARCHAR(1024),
    largeimg VARCHAR(1024)
);
Run Code Online (Sandbox Code Playgroud)

独特的索引

所以我们使用数组索引作为主键.但是为了根据主键以外的任何"列"搜索数据库,它需要一个O(n)操作:我们需要迭代整个表并检查每一行的相关值.这是索引发挥作用的地方.如果我们想在我们的县名上添加索引怎么办?好吧,我们可以使用一个单独的关联数组:

$countiesNameIndex = array();
$countiesNameIndex['Armagh'] = 1;
$countiesNameIndex['Antrim'] = 2;
Run Code Online (Sandbox Code Playgroud)

关联数组实现为哈希表,因此粗略地按键访问元素O(1).这使我们在按县名搜索时可以大大加快对行的访问速度:

$search = 'Antrim';
$result = array();
if (isset($countiesNameIndex[$search])) {
    $result[$countiesNameIndex[$search]] = $counties[$countiesNameIndex[$search]];
}
return $result;
Run Code Online (Sandbox Code Playgroud)

添加和删​​除行时,可以动态维护此索引:

// 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]
    );
}
Run Code Online (Sandbox Code Playgroud)

随着数据集变大,这种索引方法将大大加快数据访问速度.


非聚集索引

让我们快速看看我们如何实现一个非唯一索引,它不包含有关它引用的行的顺序的信息 - 实现非常相似.这将比我们的唯一索引慢一点,但明显快于迭代整个数据集:

$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]);
}
Run Code Online (Sandbox Code Playgroud)

使用多个索引

我们甚至可以使用这些索引来执行更复杂的操作 - 考虑如何实现SQL查询

SELECT *
FROM counties
WHERE name = 'Antrim'
  AND img  = 'css/images/map.jpg'
Run Code Online (Sandbox Code Playgroud)

首先我们来看一下最具体的索引(唯一索引):

$result = array();

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

if (!isset($countiesNameIndex[$nameSearch])) {
    return $result;
}
Run Code Online (Sandbox Code Playgroud)

接下来,我们检查该行是否与其他条件匹配:

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

return $result;
Run Code Online (Sandbox Code Playgroud)

您可以看到,在这种情况下,我们只需要使用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]]
);
Run Code Online (Sandbox Code Playgroud)

外键和连接表

但是当我们开始想要加入另一张桌子时呢?好吧,这就像我们在SQL中做的那样.让我们假设我们有以下SQL表定义:

CREATE TABLE walks (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(1024),
    location VARCHAR(1024),
    county INT
);
Run Code Online (Sandbox Code Playgroud)

显然我们从另一个数组开始,并插入一些行:

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

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

非常明显的是,该county列引用了$counties表中行的ID .顺便提一下,我们使用计数器来跟踪ID而不是使用$arr[] =赋值语法的原因有两个:首先,它确保当从表中删除行时ID始终是常量,其次它使得它更容易(计算成本更低) )提取最后插入的行的ID - 这将有助于创建具有外键的复杂表结构,如此处所示.

现在让我们看一下将这些数据联系起来.想象一下,我们运行了这个SQL查询:

SELECT c.*, w.*
FROM walks w
JOIN counties c ON w.county = c.id
LIMIT 0, 10
Run Code Online (Sandbox Code Playgroud)

这可以实现如下:

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

现在您可能已经发现了这个问题:两个表都包含一个名为name的列.上面的代码将返回的值namewalks表中的每一行.您可以轻松调整此行为,但具体如何实现这将取决于您想要的结果.


订购结果集

PHP提供了一个功能,可以在这里完成大部分工作 - array_multisort().最重要的一点是,在提取结果行之后应该应用顺序,以最小化所需操作的数量.

SELECT c.*, w.*
FROM walks w
JOIN counties c ON w.county = c.id
ORDER BY w.location ASC
Run Code Online (Sandbox Code Playgroud)
// 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;
Run Code Online (Sandbox Code Playgroud)

希望以上示例应该开始演示一些可用于使用PHP数组实现RDBMS上的某些功能的逻辑.可以进行某些相当简单的优化,即使在数据集增长时也能保持这些操作相对便宜.

  • 你回答很棒! (4认同)