Asked  7 Months ago    Answers:  5   Viewed   25 times

I've got a multidimensional associative array which includes an elements like

$data["status"]
$data["response"]["url"]
$data["entry"]["0"]["text"]

I've got a strings like:

$string = 'data["status"]';
$string = 'data["response"]["url"]';
$string = 'data["entry"]["0"]["text"]';

How can I convert the strings into a variable to access the proper array element? This method will need to work across any array at any of the dimensions.

 Answers

96

Quick and dirty:

echo eval('return $'. $string . ';');

Of course the input string would need to be be sanitized first.

If you don't like quick and dirty... then this will work too and it doesn't require eval which makes even me cringe.

It does, however, make assumptions about the string format:

<?php
$data['response'] = array(
    'url' => 'http://www.testing.com'
);

function extract_data($string) {
    global $data;

    $found_matches = preg_match_all('/["([a-z]+)"]/', $string, $matches);
    if (!$found_matches) {
            return null;
    }

    $current_data = $data;
    foreach ($matches[1] as $name) {
            if (key_exists($name, $current_data)) {
                    $current_data = $current_data[$name];
            } else {
                    return null;
            }
    }

    return $current_data;
} 

echo extract_data('data["response"]["url"]');
?>
Wednesday, March 31, 2021
 
VitaCoco
answered 7 Months ago
94

To add to Rikesh's answer:

<?php
$aryMain = array(array('hello','bye'), array('',''),array('','')); 
$aryMain = array_filter(array_map('array_filter', $aryMain));
print_r($aryMain);

?>

Sticking his code into another array_filter will get rid of the entire arrays themselves.

Array
(
    [0] => Array
        (
            [0] => hello
            [1] => bye
        )

)

Compared to:

$aryMain = array_map('array_filter', $aryMain);

Array
(
    [0] => Array
        (
            [0] => hello
            [1] => bye
        )

    [1] => Array
        (
        )

    [2] => Array
        (
        )

)
Wednesday, March 31, 2021
 
drowneath
answered 7 Months ago
29

Based on your given code, we can reverse-engineer the structure of $arr2 to (assuming R, G and B are integer from 0 to 255):

$arr2 = array(
   0 => array(
      0 => array(
        "R" => 128,
        "G" => 64,
        "B" => 255
      ),
      1 => array(
        ...
      ) 
   )
);

Given that your $SIZE is set to 256, you will have a total of 256*256=65536 arrays further containing arrays with key-values for R, G and B, resulting in total of 256*256*3=196608 integers in 3 levels of hierarchy. No surprise your code is slow!

I think the best strategy here is to try to reduce the total number of items in your array.

Given that instead of encoding single cells as "R, G, B" triples, you could encode all values in a single integer. Such as instead of:

0 => array( "R" => $r, "G" => $g, "B" => $b )

Given that 0<=r,g,b<=255, you could encode $arr2 as:

0 => ($r<<16 + $g<<8 + $b);

Now of course you need to unpack the color value inside your loop as well. This can be achieved by:

$col = $arr2[$y][$x];
$col_b = ($col&255);
$col_g = ($col>>8)&255;
$col_r = ($col>>16)&255;
$r .= $col_r.":";
$g .= $col_g.":";
$b .= $col_b.":";

This modification alone would cut one level of hierarchy from your array completely.

While running your original code with $SIZE=256, my average execution speed in my settings was 0.30 secs. With the given refactoring, I was able to reduce this to 0.10 secs cutting your calculation time to 1/3 of the original.

You will still have a lot of work to do if you wish to improve the performance, but I hope this gives you an idea on how you could proceed.

Saturday, May 29, 2021
 
drowneath
answered 5 Months ago
42

As your template string must get reference to the b variable dynamically (in runtime), so the answer is: NO, it's impossible to do it without dynamic code generation.

But, with eval it's pretty simple:

let tpl = eval('`'+a+'`');
Tuesday, June 1, 2021
 
SkyNet
answered 5 Months ago
62

Actually the Python regular expression library already provides the general functionality you are asking for. You just have to change the syntax of the pattern slightly

>>> import re
>>> from operator import itemgetter
>>> mystr='Version 1.15.6n'
>>> m = re.match('Version (?P<_0>.+).(?P<_1>.+).(?P<_2>.+)', mystr)
>>> map(itemgetter(1), sorted(m.groupdict().items()))
['1', '15', '6']

As you can see, you have to change the (un)format strings from {0} to (?P<_0>.+). You could even require a decimal with (?P<_0>d+). In addition, you have to escape some of the characters to prevent them from beeing interpreted as regex special characters. But this in turm can be automated again e.g. with

>>> re.sub(r'\{(d+)\}', r'(?P<_1>.+)', re.escape('Version {0}.{1}.{2}'))
'Version\ (?P<_0>.+)\.(?P<_1>.+)\.(?P<_2>.+)'
Monday, August 2, 2021
 
Fanda
answered 3 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :