2012-01-13 36 views
-3

我想和大家分享一下我創建的功能,以瞭解如何優化它,或者是否有更好的方法來實現這一點。你如何將密鑰,值對的散列平坦化?

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 ...不關注這些!

+2

爲什麼你使用像'isHash','getKeys','getValues'這樣的函數?這是公司標準的一部分嗎?你可以不使用簡單的數組和哈希來代替引用嗎? – Borodin 2012-01-13 23:42:18

回答

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

我認爲這應該工作!

+0

它錯過了逃跑。如果你的鍵或值包含字符的[很長的列表](https://metacpan.org/module/URI:Escape)中的任何一個,這將會炸燬。 – hobbs 2012-01-13 23:16:44

+0

@ hobbs,是的,謝謝! – cirne100 2012-01-13 23:21:54

+0

@nodebunny,無模塊地使用正則表達式來匹配所有不安全的字符,並用代表的十六進制數代替!像這樣(或者非常接近!)s /([^ [\ w - \。\〜]])/ sprintf(「%02X」,ord $ 1)/ eg; – cirne100 2012-01-14 01:55:41

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,map和join。

+2

@nodebunny如果你在奇怪的限制下工作,你應該在你的問題中提及它們。如果您不願意使用該模塊,請訪問http://search.cpan.org/perldoc?URI,查看源代碼並獲取所需內容。 – TLP 2012-01-14 16:19:16

+1

@nodebunny似乎你不知道「扁平」這個詞的意思。在perl中拼湊散列的方式是'@kv =%hash'。 – hobbs 2012-01-14 19:25:56

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

這就是爲什麼我說「我看不到任何問題......」。