2010-05-25 4 views
20

Jeśli mam skrót w Perlu, który zawiera pełne i sekwencyjne mapowania całkowite (tj. Wszystkie klucze od 0 do n są odwzorowane na coś, bez kluczy poza tym), czy istnieje sposób przekształcając to w tablicę?Perl, przekonwertuj hasz na tablicę

Wiem, że mógłbym powtórzyć parami klucz/wartość i umieścić je w nowej tablicy, ale coś mówi mi, że powinien istnieć wbudowany sposób robienia tego.

+4

** RANT OSTRZEŻENIE! ** Dlaczego każdy chce sortować klucze? Nie ma takiej potrzeby i sprawia, że ​​algorytm jest o wiele wolniejszy! Sortowanie jest powolne! ** Odpowiedź runrig ** jest najlepsza tutaj. Będzie działać, jeśli skrót jest skąpy. Tablice zachowują porządek, ale są strukturami dostępu losowego. Nie pracujemy z połączonymi listami, ludźmi! – daotoad

+0

Masz rację: jest sposób, aby to zrobić. Patrz [Odpowiedź Ether'a] (http://stackoverflow.com/questions/2907270/perl-convert-hash-to-array/2907469#2907469). :) To pytanie jest kolejnym powodem, dla którego istnieje różnica między kontekstem listy a tablicami.W połączeniu z plasterkami umożliwia konwersję między listami i hashe bez specjalnej magii lub iteracji, a imho jest jedną z najpotężniejszych funkcji Perla. –

Odpowiedz

20

Jeśli oryginalne źródło danych jest hash:

# first find the max key value, if you don't already know it: 
use List::Util 'max'; 
my $maxkey = max keys %hash; 

# get all the values, in order 
my @array = @hash{0 .. $maxkey}; 

Lub, jeśli oryginalne dane źródłem jest hashref:

my $maxkey = max keys %$hashref; 
my @array = @{$hashref}{0 .. $maxkey}; 

Łatwo to sprawdzić za pomocą tego przykładu:

my %hash; 
@hash{0 .. 9} = ('a' .. 'j'); 

# insert code from above, and then print the result... 
use Data::Dumper; 
print Dumper(\%hash); 
print Dumper(\@array); 

$VAR1 = { 
      '6' => 'g', 
      '3' => 'd', 
      '7' => 'h', 
      '9' => 'j', 
      '2' => 'c', 
      '8' => 'i', 
      '1' => 'b', 
      '4' => 'e', 
      '0' => 'a', 
      '5' => 'f' 
     }; 
$VAR1 = [ 
      'a', 
      'b', 
      'c', 
      'd', 
      'e', 
      'f', 
      'g', 
      'h', 
      'i', 
      'j' 
     ]; 
+0

Nie ma operatora '->' dla hashref? – Zaid

+0

@Zaid: nie, to nie jest tak, jak używasz plasterków w hashrefach. – Ether

+1

Silly me, to jest rzucanie jako tablica, dlatego operator strzałki nie jest potrzebny. – Zaid

12

OK, to nie jest bardzo "wbudowane", ale działa. To także IMHO preferuje dowolne rozwiązanie z "sortowaniem", ponieważ jest szybsze.

map { $array[$_] = $hash{$_} } keys %hash; # Or use foreach instead of map 

W przeciwnym razie, mniej wydajne:

my @array = map { $hash{$_} } sort { $a<=>$b } keys %hash; 
+6

lub aby uniknąć mapy w pustym kontekście: $ array [$ _] = $ hash {$ _} dla kluczy% hash; – runrig

+3

To musiałoby być "sort {$ a <=> $ b}". Pamiętaj, że 'sort' domyślnie porównuje łańcuchy. – Zaid

2

To pozostawi klucze nie zostały zdefiniowane w %hashed_keys jak undef:

# if we're being nitpicky about when and how much memory 
# is allocated for the array (for run-time optimization): 
my @keys_arr = (undef) x scalar %hashed_keys; 

@keys_arr[(keys %hashed_keys)] = 
    @hashed_keys{(keys %hashed_keys)}; 

A jeśli używasz nazwy:

@{$keys_arr}[(keys %{$hashed_keys})] = 
    @{$hashed_keys}{(keys %{$hashed_keys})}; 

Lub, bardziej niebezpiecznie, ponieważ zakłada to, co mówisz, że jest prawdą (nie zawsze może to być prawda i błąd; Po prostu powiedzmy!):

@keys_arr = @hashed_keys{(sort {$a <=> $b} keys %hashed_keys)}; 

Ale to jest poza tym punktem. Jeśli są na początku indeksowane liczbami całkowitymi, dlaczego są teraz w haszymku?

+0

Dobre wykorzystanie plasterków. Również dobry punkt dotyczący początkowego wyboru struktury danych. Szkoda, że ​​wychowałeś "sortowanie", sortowanie jest powolne (patrz moja rant powyżej) i podatne na błędy i nie jest pożądane. – daotoad

+0

@daotoad - Pierwsze (i zalecane) rozwiązanie nie używa "sortowania". Ale całkowicie zgadzam się z "sortowaniem"; generuje do n-kwadratowych dowolnych wywołań funkcji na inwokację [wskazówka: to jest straszne]. – amphetamachine

12

Można wyodrębnić wszystkie wartości z tablicy asocjacyjnej z values funkcję:

my @vals = values %hash; 

Jeśli chcesz je w określonej kolejności, a następnie można umieścić przyciski w odpowiedniej kolejności, a następnie podjąć hash slice z że:

my @sorted_vals = @hash{sort { $a <=> $b } keys %hash}; 
0

Jak powiedział DVK, nie ma zbudowany w sposób, ale będzie to rade:

my @array = map {$hash{$_}} sort {$a <=> $b} keys %hash; 

lub to:

my @array; 

keys %hash; 

while (my ($k, $v) = each %hash) { 
    $array[$k] = $v 
} 

odniesienia, aby zobaczyć co jest szybsze, moje przypuszczenie byłoby sekund.

+0

Cóż, pierwszym będzie O (NlogN) średnio, ale aż do O (N^2). Druga metoda to po prostu O (N). Nie ma potrzeby stosowania benchmarków. – daotoad

4

Perl nie zapewnia wbudowanego rozwiązania, aby rozwiązać problem.

Jeśli wiesz, że klucze obejmować konkretny zakres 0..N, można wykorzystać ten fakt:

my $n = keys(%hash) - 1; 
my @keys_and_values = map { $_ => $hash{$_} } 0 .. $n; 
my @just_values  = @hash{0 .. $n}; 
+0

Lub 'mój $ n = $ # {[klucze% hash]}' jeśli masz awersję do stałej odejmowania ... – Zaid

0

Łączenie FM „s i Ether” odpowiedziami s pozwala uniknąć definiowania inaczej niepotrzebnego skalarne:

my @array = @hash{ 0 .. $#{[ keys %hash ]} }; 

Schludny rzeczą jest to, że w przeciwieństwie do z podejściem scalar, działa powyżej, nawet w mało prawdopodobnym przypadku, gdy domyślny indeks pierwszego elementu, $[, jest niezerowy.

Oczywiście oznaczałoby to pisząc coś głupiego i ukrywane tak:

my @array = @hash{ $[ .. $#{[ keys %hash ]} }; # Not recommended 

Ale wtedy zawsze istnieje zdalnego szansa że ktoś musi go gdzieś (WinCE) ...

1
$Hash_value = 
{ 
'54' => 'abc', 
'55' => 'def', 
'56' => 'test', 
}; 
while (my ($key,$value) = each %{$Hash_value}) 
{ 
print "\n $key > $value"; 
} 
0

Możemy napisać trochę czasu, jak poniżej:

$j =0; 
while(($a1,$b1)=each(%hash1)){ 
    $arr[$j][0] = $a1; 
    ($arr[$j][1],$arr[$j][2],$arr[$j][3],$arr[$j][4],$arr[$j][5],$arr[$j][6]) = values($b1); 
    $j++; 
} 

$ a1 zawiera klucz i $ b1 zawiera wartości W powyższym przykładzie mam Hash z tablicy, a tablica zawiera 6 elementów.

0

Prostym sposobem jest wykonanie @array = %hash

Przykładowo

my %hash = (
    "0" => "zero", 
    "1" => "one", 
    "2" => "two", 
    "3" => "three", 
    "4" => "four", 
    "5" => "five", 
    "6" => "six", 
    "7" => "seven", 
    "8" => "eight", 
    "9" => "nine", 
    "10" => "ten", 
); 

my @array = %hash; 

print "@array"; będzie następujący wynik,

3 trzy 9 dziewięć 5 pięć 8 osiem 2 dwa 4 cztery 1 jeden 10 dziesięć 7 siedem 0 zero 6 sześć