通过多个索引引用PHP数组

10

这可能是某种奇怪的长快捷方式,如果我在思路上错了,请纠正我...

我有一个数据矩阵,看起来像:

unique_id | url | other random data...
unique_id | url | other random data...
unique_id | url | other random data...

我希望能够通过网址或唯一标识符引用一个项目 - 是否有更好的方法实现?

我想也可以采用两个数组的欺骗性解决方案,但我想知道是否有更好的方法。


2
不是的,只需要创建两个数组即可。开销很小(取决于你的数组有多大)。 - El Yobo
一旦“随机数据”进入数组,您需要修改它吗?唯一标识符和URL是否可能发生冲突? - Matthew Flaschen
不要重复“其他随机数据”(DRY概念)。最干净的解决方案是拥有一个数组,将unique_id映射到“其他随机数据”,然后再有一个数组将url映射到unique_id。这就是unique_id的目的:提供一个简洁高效的“句柄”,代表给定记录(行)的数据。 - ToolmakerSteve
4个回答

14

我能想到的不需要为每次搜索迭代数组(参见Jacob的答案)的唯一方法是在两个数组中存储对每个项的引用。

编辑:由于URL和ID不能发生冲突,因此它们可以存储在同一个引用数组中(感谢Matthew)

$items; // array of item objects
        // Use objects so they're implicitly passed by ref

$itemRef = array();

foreach ($items as $item) {
    $itemRef[$item->unique_id] = $item;
    $itemRef[$item->url] = $item;
}

// find by id
$byId = $itemRef[$id];

// find by url
$byUrl = $itemRef[$url];

你可以使用实现了getById()getByUrl()方法的集合类来封装这个功能。在内部,它可以使用需要的数组存储引用。

当然,你所做的基本上是创建索引结果集,这是最好留给数据库管理系统处理的事情。


1
另外,如果您选择,您可以将它们放在同一个数组中(例如 $items)。这可能会稍微有些混淆,但是Bob说键不会发生冲突。 - Matthew Flaschen
哦,那很有趣。它们不会发生冲突,但从漏洞的角度来看似乎有点可怕(例如使用URL而不是唯一ID强制进行查找)。不过这是一个不错的技巧。 - Jane Panda
@Bob,这就像使用fetch_both方法检索数据库记录时一样,结果包含数字和字符串索引。说到索引,如果这些数据来自数据库,最好将ID和url字段应用索引,并执行单个提取以检索指定的记录。 - Phil
@MatthewFlaschen - 你可以把它们放在同一个数组中,但是将url映射到unique_id的第二个数组更加清晰。保持不同的概念分开。 - ToolmakerSteve

3

试试这样的代码:

function selectByIdOrURL($array, $data) {
    foreach($array as $row) {
       if($row['unique_id'] == $data || $row['url'] == $data) return $row;
    }
    return NULL;
}

$array = array(
           array('unique_id' => 5, 'url' => 'http://blah.com'),
           array('unique_id' => 3, 'url' => 'http://somewhere_else.com')
         );
$found = selectByIdOrURL($array, 5); //array('unique_id' => 5, 'url' => 'http://blah.com')
$nfound = selectByIdOrURL($array, 10); //NULL

1
迭代数据的唯一方式是什么?我想这不是一个很大的问题,但我真的很好奇是否可以为数组(一般而言)有多个索引。 - Jane Panda
2
@Bob,不,数组没有多个索引的方法。 - Jacob Relkin
3
一般来说,不需要。最快的方法(用于访问时间)是使用两个数组,一个以unique_id作为键,另一个以URL为键,两个数组都将所有数据作为值。 Jacob的答案会使用稍少的内存,但每次引用某个元素时都需要遍历整个数组;我的方法会使用稍多一些的内存,但可以更快地检索结果。 - El Yobo
1
真遗憾...我猜只是迭代它也不那么糟糕。 - Jane Panda
任何花哨的解决方案都需要在幕后进行迭代。 - Isaac Lubow

1
似乎您的高端解决方案只在PHP 5.5及以上版本中可用。 您可以结合使用array_searcharray_column,以单行代码获取条目。
$items = [
    [
     'unique_id' => 42,
     'url' => 'http://foo.com'
    ],
    [
     'unique_id' => 57,
     'url' => 'http://bar.com'
    ],
    [
     'unique_id' => 36,
     'url' => 'http://example.com'
    ],

];

$bar = $entries[array_search(57, array_column($items, 'unique_id'))];

var_dump($bar);

//outputs
array (size=2)
    'unique_id' => int 57
    'url' => string 'http://bar.com' (length=14)

0

肯定一个对象会更容易吧?

class Item {
    public $unique_url;
    public $url;
    public $other_data;

    public function __construct($unique_url, $url, $other_data)
    {
        $this->unique_url = $unique_url;
        $this->url = $url;
        $this->other_data = $other_data;
    }
}



class ItemArray {
    private $items = array();

    public function __construct()
    {
    }

    public function push(Item $item)
    {
        array_push($items, $item); //These may need to be reversed
    }

    public function getByURL($url)
    {
        foreach($items as $item)
        {
            if($item->url = $url)
            {
                return $item;
            }
        }
    }

    public function getByUniqueURL($url)
    {
        foreach($items as $item)
        {
            if($item->unique_url = $unique_url)
            {
                return $item;
            }
        }
    }

}

然后与之一起使用

$itemArray = new ItemArray();
$item = new Item("someURL", "someUniqueURL","some other crap");
$itemArray->push($item);

$retrievedItem = $itemArray->getItemByURL("someURL");

这种技术由于对象创建而带有一些额外的开销,但除非你处理的行数非常大,否则它是可以接受的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接