你如何压扁键值对的散列?

时间:2012-01-13 22:53:41

标签: perl hash query-string

我想与你们分享一个我创建的功能,看看我如何优化它,或者是否有更好的方法来实现这一目标。

  sub flatten{
    my($ref,$delim,$item_delim,$array,$str) = @_;

    die("Required Hash Reference") unless isHash($ref);

    $delim = $delim ? $delim  :'_';

      #dump into array hash vals #simplified
      if(!$item_delim){
        @{$array} = %{$ref};
      }else{
        my($keys,$values);

        $keys = getKeys($ref);
        $values = getValues($ref);

        #item strings
        if($#$keys > 0 && $#$values > 0){
          #fix for issue where value[n] is empty
          @{$array}= map{ (defined $$values[ $_ ]) ? $$keys[ $_ ].$item_delim.$$values[ $_ ] : $$keys[ $_ ].$item_delim } 0 .. int($#$keys);
        }else{
         log "No Values to flatten";
         return '';
        }
      }

    $str = join($delim,@{$array});
    return $str;
  }

我应该注意哪些优化点?

基本上我想从

开始
$HASH => {

 key1 => 'val1',
 key2 => 'val2',
 key3 => 'val3',

}

$STRING= key1=val1&key2=val2 ...

已更新

没有模块的解决方案是首选我真的只是想知道如何有效地压扁哈希!

请注意,这里的一些函数只是包装函数,可以完成他们所说的。 isHash getKeys ...不注意那些!

4 个答案:

答案 0 :(得分:6)

一种方便的方法是使用URIquery_form工具。

use URI;

my $uri = URI->new("", "http"); # We don't actually care about the path...
$uri->query_form(%params);
my $query_string = $uri->query;

另一种更手动的方法是使用URI::Escape,地图和加入。

答案 1 :(得分:3)

没有模块:

my $hashref = {    
  key1 => 'val1',
  key2 => 'val2',
  key3 => 'val3',  
};

sub encode {
  my $str = shift;
  $str =~ s/([^A-Za-z0-9\.\/\_\-])/sprintf("%%%02X", ord($1))/seg;
  return $str;
}

my $str = join '&' => map { encode($_).'='.encode($hashref->{$_}) } grep { defined $hashref->{$_} } keys %$hashref;

结果:

key2=val2&key1=val1&key3=val3

答案 2 :(得分:3)

我在你的问题中看不到任何东西,这意味着你的子程序需要比以下更复杂:

sub flatten {
  my ($hash, $delim, $item_delim) = @_;

  $delim //= '&',
  $item_delim //= '=';

  return join $delim, map { "$_$item_delim$hash->{$_}" } keys %$hash;
}

更新:在此处获取一些downvotes。我假设人们反对我不是任何URI编码的事实。我只想指出原始问题中没有任何内容表明我们正在构建URI。如果我知道我们是,那么我当然会使用appropriate module

这就是为什么我说“我在你的问题中看不到任何东西......”。

答案 3 :(得分:0)

use URI::Escape;
my $str=join '&',map {uri_escape($_).'='.uri_escape($QUERY_STRING->{$_})} grep {defined $QUERY_STRING->{$_}} keys %$QUERY_STRING;

我认为这应该有效!