【问题标题】:How to this accomplish writing crafty array writing function?这个如何完成编写狡猾的数组写入功能?
【发布时间】:2011-11-08 19:13:55
【问题描述】:

编辑

我知道我是这里的新海报,但我对 StackOverflow 并不陌生。正如我在下面看到的那样,我从未见过人们对问题提出全新的解决方案。我提供了输入、输出和预期输出。接受的答案将在这些准则范围内起作用。


我正在尝试编写一个如下所述的数组写入函数

// 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);

输出

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

)

哦不!宝可梦训练师是谁? Ash Ketchum 被遗忘了!


我明白它为什么会中断,但我不知道应该如何编写这个函数。我感觉到需要递归,但我不确定如何实现它:\

输出应该

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

)

【问题讨论】:

  • 我没有看到描述。这段代码应该做什么?也就是说,输入是什么,输出应该是什么?
  • @JimMischel 抱歉,我添加了预期的输出。
  • 我不记得 Ash 曾经训练过 Diglett。

标签: php arrays algorithm recursion


【解决方案1】:

似乎使用对象会容易得多。

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

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

var_dump($config);

或者更好的是,创建一个自定义类,该类的行为完全符合您对方法和受保护数据的要求。

编辑:

也许是这样的。你当然可以让它随心所欲。

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

【讨论】:

    【解决方案2】:
    $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;
    }
    

    用法:

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

    通过引用操作符进行编辑:

    // 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);
    

    新用法:

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

    【讨论】:

    • 它是一个递归函数,这就是为什么您需要将配置添加为输入而不是依赖全局关键字的原因。请记住,如果您连续调用 set('foo', 'test'); set('foo:bar', 'test'); 之类的,它将给您一个错误,正如您所期望的那样。
    • 您还可以在参数中使用 $config 旁边的 & 引用运算符,以避免每次使用该函数时都需要设置配置。
    • 这也可以让你像set('foo:bar:baz', 'somevalue');这样打电话
    【解决方案3】:

    当您执行set("pokemon:???", "someVal"); 时,您正在覆盖$config 中的前一组pokemon 数组。也许你可以在key中添加某种计数器/id

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

    【讨论】:

    • 正如我所说,我理解为什么会发生这种情况......我只是不知道如何让它按预期工作。
    • 不,您不能为密钥添加计数器。用户将期望根据他们输入的相同键检索值。
    • 碎纸机,我提供了预期的输出。
    • 谢谢。这不是对我有用的解决方案,但它促使我找到合适的解决方案。我的代表少于 100,所以我无法回答自己的问题。相反,我在 OP 中添加了一个编辑。
    【解决方案4】:
    $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);
    

    只要您的输入中只有一个 : ,就可以了。

    【讨论】:

    • 谢谢你,但用​​户可以在他们的密钥中指定任意数量的:
    • 太糟糕了。很抱歉这没有帮助。
    • 为 OP 添加了正确答案。
    【解决方案5】:

    现在我有超过 100 个代表,我终于可以将其发布为真正的答案并将其标记为已接受。

    这是一个非常整洁的小sn-p :)

    // 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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多