¿Cómo lograr esto escribiendo la función de escritura de matriz astuta?

EDITAR

I know I'm a new poster here, but I'm not new to StackOverflow. I've never seen people make up completely new solutions to problems as I'm seeing below. I provided the input, the output, and the expected output. The accepted answer will work within these guidelines.


I have am trying to write an array writing function that works as described below

// existing array
$config = array("preserve" => "please");

function set($key, $value){
    global $config;
    if(count($keys = explode(':', $key)) > 1){
        $key = array_shift($keys);
        while($k = array_pop($keys)){
            $value = array($k => $value);
        }
    }
    return $config[$key] = $value;   
}

// set
set("foo", "bar");
set("pokemon:trainer", "ashk");
set("pokemon:favorite", "diglett"); // overwrites pokemon:trainer :(

print_r($config);

Salida

Array
(
    [preserve] => please
    [foo] => bar
    [pokemon] => Array
        (
            [favorite] => diglett
        )

)

Oh no! Who's the pokemon trainer? Ash Ketchum has been forgotten!


I understand why it's breaking, but I can't find out how I should write this function. I sense the need for recursion, but I'm not sure how to implement it :\

Salida debemos be

Array
(
    [preserve] => please
    [foo] => bar
    [pokemon] => Array
        (
            [trainer] => ashk
            [favorite] => diglett
        )

)

preguntado el 08 de noviembre de 11 a las 19:11

I don't see a description. What is this code supposed to do? That is, what is the input and what is the output supposed to be? -

@JimMischel Sorry about that, I added the expected output. -

I don't remember Ash ever training Diglett. -

5 Respuestas

seems like working with objects would be much easier.

$config = new stdClass();
$config->preserve = 'please';
$config->foo = 'bar';

$config->pokemon = new stdClass();
$config->pokemon->trainer= 'ashk';
$config->pokemon->favorite = 'diglette';

var_dump($config);

or better yet, create a custom class that behaves exactly how you want with methods and protected data.

Edit:

maybe something like this. you could of course make it behave however you like.

class config {
   protected $preserve;
   protected $data = array();
   protected $pokemonData = array();

   public function __construct($preserve) {
      $this->preserve = $preserve;
   }

   public function set($key, $value) {
      $this->data[$key] = $value;
   }

   public function setPokemon($key, $value) {
      $this->pokemonData[$key] = $value;
   }

   public function get($key) {
      if (isset($this->data[$key]) === true) {
         return $this->data[$key];
      } else {
         return false;
      }
   }

   public function getPokemon($key) {
      if (isset($this->pokemonData[$key]) === true) {
         return $this->pokemonData[$key];
      } else {
         return false;
      }
   }

   public function getAsArray() {
      $output = array(
         'preserve' => $this->preserve,
         'pokemon' => $this->pokmonData
      );
      return $output + $this->data;
   }
}

respondido 09 nov., 11:00

$config = array('preserve' => 'please');

function set($config, $key, $value) {
    $keys = explode(':', $key);
    $left_key = array_shift($keys);
    if (count($keys) === 0) {
        $config[$left_key] = $value;
    } else {
        if (isset($config[$left_key]) === false) $config[$left_key] = array();
        $config[$left_key] = set($config[$left_key], implode(':', $keys), $value);
    }
    return $config;
}

uso:

$config = set($config, $key, $value);

edit with pass by reference operator:

// change to this
function set(&$config, $key, $value) {

// also this line
$config[$left_key] = set($config[$left_key], implode(':', $keys), $value);
// would then need to be this instead
set($config[$left_key], implode(':', $keys), $value);

new usage:

set($config, $key, $value);

respondido 10 nov., 11:03

its a recursive function, which is why you need to add the config as an input instead of relying on the global keyword. keep in mind if you do successive calls like set('foo', 'test'); set('foo:bar', 'test'); it will give you an error, as you should expect. - dqhendricks

también puedes usar el & reference operator next to $config in the arguments to avoid needing to set the config each time you use the function. - dqhendricks

this also allows you to do calls like set('foo:bar:baz', 'somevalue'); - dqhendricks

Cuando tu lo hagas set("pokemon:???", "someVal"); you are writing over the previous set pokemon matriz dentro $config. Perhaps you can add some kind of counter/id in the key

function set($key, $value){
    global $config;
    if(count($keys = explode(':', $key)) > 1){
        $key = array_shift($keys);
        while($k = array_pop($keys)){
            $value = array($k => $value);
        }
        $config[$key][] = $value;
        return;
    }
    $config[$key] = $value;   
}

respondido 08 nov., 11:23

As I said, I understand el porqué it's happening... I just don't know how to make it work as expected. - Mulan

No, you can't add a counter to the key. The user will be expecting to retrieve the value based on the same key they entered. - Mulan

Shredder, I provided the expected output. - Mulan

thank you. This is not the solution that worked for me, but it prompted me to arrive at the proper one. I have less than 100 rep so I can't answer my own question. Instead, I added an edit to the OP. - Mulan

$config = array("preserve" => "please");

function set($key, $value){
    global $config;
    if(strpos($key,':')==true) { 
        $config[substr($key,0,strpos($key,':'))][substr($key,strpos($key,':')+1)] = $value;
    }
    else {
        $config[$key] = $value;
    }
}
set("foo", "bar");
set("pokemon:trainer", "ashk");
set("pokemon:favorite", "diglett"); // overwrites pokemon:trainer :(

print_r($config);

As long as you only have one : in your input, this works.

respondido 08 nov., 11:23

Thank you for this, but the user could specify as many : in their key as they'd like. - Mulan

Too bad. I'm sorry this didn't help. - pts-3

Added the proper answer to the OP. - Mulan

Now that I have over 100 rep, I can finally post this as a real answer and mark it as accepted.

This is quite a neat little snippet :)

// existing array
$config = array("preserve" => "please");

function set($key, $value){
    global $config;
    if(count($keys = explode(':', $key)) > 1){
        $key = array_shift($keys);
        while($k = array_pop($keys)){
            $value = array($k => $value);
        }
        // *** fixed here ***
        // merge new data with possible existing data
        if(array_key_exists($key, $config)){
            $value = array_merge_recursive($config[$key], $value);
        }
    }
    return $config[$key] = $value;   
}

// set
set("foo", "bar");
set("pokemon:trainer", "ashk");
set("pokemon:favorite", "diglett"); // no longer overwrites pokemon:trainer :)

print_r($config);

Respondido 24 Feb 17, 05:02

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.