2

I have an array with around 3500 array items inside it, the format being below. I have two dynamic variables that change and I need to search the array to find out row price_value based on already knowing price_slot and country.

I've currently got the below but this is taking too long. Is there anyway I can speed up this access?

PHP Function

$country = US;
$priceSlot = 3;
$priceValue = getPriceValue($priceSlot, $country);


function getPriceValue($priceSlot, $country) {
    // Search in array for price
    foreach ($array as $arrayItem) {
        if ($arrayItem['price_slot'] == $priceSlot && $arrayItem['country'] == $country) {
            return $arrayItem['price_value'];
        }
    }
    return null;
}

Snippet of Array

Array
(
    [0] => Array
        (
            [price_slot] => 1
            [base_price] => Get in Touch
            [country] => US
            [price_multiplier] => 
            [price_value] => Get in Touch
        )

    [1] => Array
        (
            [price_slot] => 2
            [base_price] => 9000
            [country] => US
            [price_multiplier] => 1.3
            [price_value] => 11700
        )

    [2] => Array
        (
            [price_slot] => 3
            [base_price] => 12000
            [country] => US
            [price_multiplier] => 1.3
            [price_value] => 15600
        )

    [3] => Array
        (
            [price_slot] => 4
            [base_price] => 15000
            [country] => US
            [price_multiplier] => 1.3
            [price_value] => 19500
        )

    [4] => Array
        (
            [price_slot] => 5
            [base_price] => 4000
            [country] => US
            [price_multiplier] => 1.3
            [price_value] => 5200
        )

    [5] => Array
        (
            [price_slot] => 6
            [base_price] => 1600
            [country] => US
            [price_multiplier] => 1.3
            [price_value] => 2080
        )

Is there any faster way to get around this?

Thanks!

5
  • How do you fill your array? If you're always checking on price_slot and country, you might be able to use that combination as the array index when building the array, instead of using a numeric index. Then you can simply use isset() to check if it exists, and return its price_value. Commented Apr 12, 2017 at 20:57
  • looks like this should be in a DB Commented Apr 12, 2017 at 21:00
  • I fill the array via csv @rickdenhaan so can't dynamically check that unfortunately! Commented Apr 12, 2017 at 21:00
  • Do you fill the array dynamically each time? That's most likely the reason it is slow Commented Apr 12, 2017 at 21:05
  • 1
    @EmilioGort, no its not. Commented Apr 12, 2017 at 21:08

3 Answers 3

3

I'm still trying to think of another way, but this is faster:

$result = array_filter($array, function($v) use($priceSlot, $country) {
                                   return ($v['price_slot'] == $priceSlot && 
                                           $v['country']    == $country);
                               });

Then you would need to access:

echo current($result)['price_value'];

You can get the price_value in $result like this:

array_filter($array, function($v) use(&$result, $priceSlot, $country) {
                         $result = ($v['price_slot'] == $priceSlot &&
                                    $v['country']    == $country) ?
                                    $v['price_value'] : null;
                     });
Sign up to request clarification or add additional context in comments.

Comments

0

A possible solution is by indexing your array (the same thing your database does). By creating an multidimensional array, containing the indexes you're searching on, you'll be able to return the correct entry immediately. You'll definitely see a performance increase when you have to get price value for more than 1 entry (since indexing costs 1 full iteration). Beware that this technique is especially meant for indexing objects, indexing array-values costs more memory.

An example for indexing your array:

$index = array();

foreach ($array as $entry) {
    $country = $index['country'];
    $priceSl = $index['price_slot'];

    if (!isset($index[$country][$pricelSl])) {
        $index[$country][$pricelSl] = array();
    }

    $index[$country][$pricelSl][] = $entry;
}

The next step is to grab the entry from the index:

function getPriceValue($country, $priceSlot) use ($index) {
    if (isset($index[$country][$pricelSl])) {
        // Return the first entry, we could have more theoretically.
        return reset($index[$country][$pricelSl]);
    }

    return null;
}

TL;DR: 1 full iteration required. Increasing performance when retrieving more than 1 element. Speed of O(1).

Comments

0

Why not create a keyed version of your array at the time you load the data?

foreach ($array as $arrayItem) {
    $hash[$arrayItem['price_slot'] . $arrayItem['country']][] = $arrayItem;
}

After that, looking up an entry by price slot and country can be done in constant time:

function getPriceValue($priceSlot, $country) {
    return $hash[$priceSlot . $country][0]['price_value'];
}

Of course, this is only useful if you are doing more than one lookup.

NB: The middle array level is only necessary of you want to copy with situations where a given price slot and country does not uniquely define a record.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.