2010-05-25 43 views
20

Nếu tôi có băm trong Perl chứa ánh xạ nguyên hoàn chỉnh và tuần tự (nghĩa là tất cả các phím từ 0 đến n được ánh xạ tới thứ gì đó, không có khóa nào bên ngoài), có phương tiện chuyển đổi này thành một mảng?Perl, chuyển đổi băm thành mảng

Tôi biết tôi có thể lặp qua các cặp khóa/giá trị và đặt chúng vào một mảng mới, nhưng có điều gì đó cho tôi biết phải có phương tiện tích hợp để thực hiện việc này.

+4

** CẢNH BÁO RANT! ** Tại sao mọi người muốn sắp xếp các phím? Không cần và nó làm cho thuật toán chậm hơn rất nhiều! Sắp xếp chậm! Câu trả lời của ** runrig ** là câu trả lời hay nhất ở đây. Nó sẽ hoạt động nếu giá trị băm nhỏ. Mảng duy trì trật tự nhưng chúng là các cấu trúc truy cập ngẫu nhiên. Chúng tôi không làm việc với danh sách liên kết, mọi người! – daotoad

+0

Bạn nói đúng: có cách để thực hiện nó. Xem [Câu trả lời của Ether] (http://stackoverflow.com/questions/2907270/perl-convert-hash-to-array/2907469#2907469). :) Câu hỏi này là một lý do khác tại sao có sự khác biệt giữa ngữ cảnh danh sách và mảng.Cùng với các slice, nó cho phép bạn thực hiện chuyển đổi giữa các danh sách và các hash mà không cần bất kỳ phép thuật hoặc phép lặp nào đặc biệt, và imho là một trong những tính năng mạnh mẽ nhất của Perl. –

Trả lời

20

Nếu nguồn dữ liệu ban đầu của bạn là một 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}; 

Hoặc nếu dữ liệu ban đầu của bạn nguồn là một hashref:

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

này rất dễ dàng để kiểm tra sử dụng ví dụ này:

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

Không có toán tử '->' nào cho hashref? – Zaid

+0

@ Zaid: không, đó không phải là cách bạn sử dụng các slice trong hashrefs. – Ether

+1

Ngớ ngẩn cho tôi, nó được đúc như một mảng, đó là lý do tại sao các nhà điều hành mũi tên là không cần thiết. – Zaid

12

OK, đây không phải là rất "tích hợp" nhưng hoạt động. Nó cũng là IMHO thích hợp hơn với bất kỳ giải pháp liên quan đến "sắp xếp" vì nó nhanh hơn.

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

Nếu không, kém hiệu quả:

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

hoặc để tránh ánh xạ trong ngữ cảnh trống: $ array [$ _] = $ hash {$ _} cho khóa% hash; – runrig

+3

Đó sẽ phải là một 'sắp xếp {$ a <=> $ b}'. Hãy nhớ rằng 'sort' mặc định so sánh chuỗi. – Zaid

2

này sẽ để chìa khóa không quy định tại %hashed_keys như 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)}; 

Và, nếu bạn đang sử dụng tài liệu tham khảo:

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

Hoặc, nguy hiểm hơn, vì nó giả định những gì bạn nói là đúng (nó có thể không phải lúc nào cũng đúng & hellip; Chỉ cần sayin '!):

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

Nhưng đây là loại bên cạnh điểm. Nếu chúng được lập chỉ mục số nguyên để bắt đầu, thì tại sao chúng lại trong một băm?

+0

Sử dụng tốt các lát. Cũng tốt điểm về sự lựa chọn ban đầu của cấu trúc dữ liệu. Quá xấu bạn đã đưa ra 'sắp xếp', sắp xếp chậm (xem rant của tôi ở trên) và lỗi dễ bị và không phải là mong muốn. – daotoad

+0

@daotoad - Giải pháp đầu tiên (và được khuyến nghị) không sử dụng 'sắp xếp'. Nhưng, tôi hoàn toàn đồng ý về 'loại'; nó tạo ra các cuộc gọi hàm n-squared tùy ý cho mỗi lời gọi [gợi ý: điều này thật khủng khiếp]. – amphetamachine

12

Bạn có thể trích xuất tất cả các giá trị từ một hash với values chức năng:

my @vals = values %hash; 

Nếu bạn muốn họ theo một thứ tự đặc biệt, sau đó bạn có thể đặt các phím theo thứ tự mong muốn và sau đó tham gia một hash slice từ rằng:

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

Như DVK nói, không có xây dựng vào bằng cách nào, nhưng điều này sẽ làm các trick:

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

hay này:

my @array; 

keys %hash; 

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

benchmark để xem đó là nhanh hơn, tôi đoán sẽ là thứ hai.

+0

Vâng, đầu tiên sẽ là O (NlogN) trung bình, nhưng lên đến O (N^2). Phương pháp thứ hai chỉ đơn giản là O (N). Không cần tiêu chuẩn. – daotoad

4

Perl không cung cấp tích hợp để giải quyết vấn đề của bạn.

Nếu bạn biết rằng các phím bao gồm một phạm vi cụ thể 0..N, bạn có thể tận dụng thực tế là:

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

Hoặc 'my $ n = $ # {[khóa% băm]}' nếu bạn có một sự đảo ngược với hằng số-chất nền ... – Zaid

0

Kết hợp FM 's và Ether' câu trả lời s cho phép một để tránh xác định một đại lượng vô hướng khác không cần thiết:

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

Điều gọn gàng là không giống như với cách tiếp cận scalar, $# hoạt động ở trên ngay cả trong trường hợp không chắc rằng chỉ mục mặc định của phần tử đầu tiên, $[, khác không.

Tất nhiên, điều đó có nghĩa là viết một cái gì đó ngớ ngẩn làm cho khó hiểu như vậy:

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

Nhưng sau đó luôn luôn có cơ hội xa rằng ai đó cần nó ở đâu đó (nhăn) ...

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

Chúng tôi có thể viết một thời gian như sau:

$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 chứa khóa và $ b1 chứa các giá trị Trong ví dụ trên, tôi có Hash của mảng và mảng chứa 6 phần tử.

0

Một cách dễ dàng là để làm @array = %hash

Ví dụ,

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"; sẽ cho kết quả sau,

3 ba 9 chín 5 năm 8 Tám 2 hai 4 Bốn 1 một 10 mười 7 bảy 0 không 6 sáu

Các vấn đề liên quan