【问题标题】:How do you flatten a hash of key,value pairs?你如何展平键值对的散列?
【发布时间】:2012-01-13 22:53:40
【问题描述】:

我想与你们分享我创建的一个函数,看看我可以如何优化它,或者是否有更好的方法来做到这一点。

  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...别管那些!

【问题讨论】:

  • 你为什么要使用isHashgetKeysgetValues这样的函数?这是公司标准的一部分吗?你不能用简单的数组和哈希来代替引用吗?

标签: perl hash query-string


【解决方案1】:

一种方便的方法是使用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、映射和连接。

【讨论】:

  • @nodebunny 如果您在奇怪的限制下工作,您应该在问题中提及它们。如果您不愿意使用该模块,请转到search.cpan.org/perldoc?URI 并查看源代码并获取所需的内容。
  • @nodebunny 似乎你不知道“扁平化”这个词是什么意思。 perl 中扁平化哈希的方法是@kv = %hash
【解决方案2】:

没有模块:

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

【讨论】:

    【解决方案3】:

    我在您的问题中看不到任何内容,这意味着您的子例程需要比以下内容更复杂:

    sub flatten {
      my ($hash, $delim, $item_delim) = @_;
    
      $delim //= '&',
      $item_delim //= '=';
    
      return join $delim, map { "$_$item_delim$hash->{$_}" } keys %$hash;
    }
    

    更新:在这里获得了一些反对意见。我假设人们反对我没有对任何东西进行 URI 编码这一事实。我只想指出,原始问题中没有任何内容说我们正在构建 URI。如果我知道我们是,那么我肯定会使用appropriate module

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

    【讨论】:

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

      我认为这应该可行!

      【讨论】:

      • 它缺少转义。如果您的键或值包含 pretty long list 的任何字符,这将爆炸。
      • @nodebunny,要在没有模块的情况下执行此操作,请使用正则表达式匹配所有不安全字符并将其替换为代表的十六进制数字!像这样(或非常接近!)s/([^[\w-\.\~]])/sprintf("%02X",ord $1)/eg;
      猜你喜欢
      • 2016-06-24
      • 1970-01-01
      • 1970-01-01
      • 2018-12-28
      • 2021-11-03
      • 2017-08-25
      • 2015-09-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多