Jane Panda
Jane Panda

Reputation: 1671

Reference PHP array by multiple indexes

This may be some sort of weird longer shortcut, and please correct me if I'm mistaken in this train of thought...

I have a matrix of data that looks like:

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

I want to be able to reference an item by either it's url, or it's unique_id - is there a fancy way to do this?

I suppose the cheating solution would be to just make two arrays, but I was wondering if there is a better way.

Upvotes: 10

Views: 24374

Answers (4)

Jon Story
Jon Story

Reputation: 3031

Surely an object would be the easy way?

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;
            }
        }
    }

}

Then use it with

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

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

This technique has a little extra overhead due to object creation, but unless you're doing insane numbers of rows it would be fine.

Upvotes: 0

Pierre Roudaut
Pierre Roudaut

Reputation: 1073

It appears your fancy solution was only available as of PHP 5.5. You can combine the use of array_search and array_column to fetch your entry in a single line of code:

$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)

Upvotes: 1

Phil
Phil

Reputation: 164776

Only way I can think of that doesn't involve iterating the array for each search (see Jacob's answer) is to store references to each item in two arrays.

Edit: As the URLs and IDs cannot collide, they may be stored in the same reference array (thanks 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];

You could probably encapsulate this nicely using a collection class that implements getById() and getByUrl(). Internally, it could store the references in as many arrays as is necessary.

Of course, what you're essentially doing here is creating indexed result sets, something best left to database management systems.

Upvotes: 14

Jacob Relkin
Jacob Relkin

Reputation: 163248

Try something like this:

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

Upvotes: 3

Related Questions