2009-10-13 29 views
19

Làm cách nào để duy trì thứ tự danh sách thực tế sau khi đếm sự xuất hiện của nó bằng cách sử dụng băm trong chương trình sau? Ví dụ: <DATA>Làm cách nào để duy trì thứ tự các khóa tôi thêm vào một băm Perl?

a 
b 
e 
a 
c 
d 
a 
c 
d 
b 
etc. 

Sử dụng hàm băm, tôi tính sự xuất hiện của từng phần tử.

và những gì tôi muốn là:

a 3 
b 2 
e 1 
c 2 
d 2 

nhưng chương trình sau đây cho thấy tôi khác.

my (%count, $line, @array_1, @array_2); 
while ($line = <DATA>) { 
    $count{$line}++ if ($line =~ /\S/); 
} 
@array_1 = keys(%count); 
@array_2 = values(%count); 
for(my $i=0; $i<$#array_1; $i++) 
{ 
    print "$array_1[$i]\t $array_2[$i]"; 
} 
+0

Bạn có thể vui lòng gắn thẻ mã của mình để đọc nó dễ dàng không. – Space

+0

Vì vậy, bạn đã hỏi năm câu hỏi, nhận được một loạt các câu trả lời cho tất cả chúng và không ai trong số họ đã đủ tốt để được chấp nhận, phải không? –

+0

@ Sinan: Không ... không phải là nó ...... tôi không thể tìm được nơi để thừa nhận tất cả các câu trả lời tuyệt vời .... chỉ cần tự hỏi hoặc là nó được thực hiện bằng cách thêm một bình luận hoặc là có nơi khác .... một newbie để stackoverflow cũng như perl ... Xin lỗi, tôi có thể dành chút thời gian để tìm hiểu cách tham gia tích cực vào nền tảng này ... Hầu như tất cả các câu trả lời đã cho tôi một ý tưởng mới để tìm hiểu ... và phục vụ mục đích của tôi ... – Cthar

Trả lời

13

Dữ liệu trong bảng băm được lưu trữ theo thứ tự mã băm của khóa, cho hầu hết các mục đích giống như một thứ tự ngẫu nhiên. Bạn cũng muốn lưu trữ thứ tự xuất hiện đầu tiên của mỗi khóa. Dưới đây là một cách để tiếp cận vấn đề này:

my (%count, $line, @display_order); 
while ($line = <DATA>) { 
    chomp $line;   # strip the \n off the end of $line 
    if ($line =~ /\S/) { 
     if ($count{$line}++ == 0) { 
      # this is the first time we have seen the key "$line" 
      push @display_order, $line; 
     } 
    } 
} 

# now @display_order holds the keys of %count, in the order of first appearance 
foreach my $key (@display_order) 
{ 
    print "$key\t $count{$key}\n"; 
} 
+3

IMHO đây là một giải pháp tốt hơn so với sử dụng Tie :: IxHash, mà tôi nghĩ là vượt ra ngoài các nhu cầu ban đầu của OP. Nó phù hợp hơn để sử dụng thứ tự hiển thị của các phím, như trong câu trả lời này, hoặc sử dụng 'foreach khóa $ của tôi (số lượng khóa sắp xếp%) {...}' – Ether

30

Hashes không ra lệnh, nhưng như thường lệ, CPAN cung cấp một giải pháp: Tie::IxHash

use Tie::IxHash; 
my %count; 
tie %count, 'Tie::IxHash'; 

while ($line = <DATA>) { 
$count{$line}++ if ($line =~ /\S/); 
} 

while(my($key, $value)= each %count) { 
    print "$key\t $value"; 
} 
5

Đơn giản chỉ cần:

my (%count, @order); 
while(<DATA>) { 
    chomp; 
    push @order, $_ unless $count{$_}++; 
} 
print "$_ $count{$_}\n" for @order; 
__DATA__ 
a 
b 
e 
a 
c 
d 
a 
c 
d 
b 
9

Từ perlfaq4 's trả lời cho "How can I make my hash remember the order I put elements into it?"


Làm thế nào tôi có thể làm cho hàm băm của tôi nhớ thứ tự mà tôi đưa các phần tử vào đó?

Sử dụng Tie :: IxHash từ CPAN.

use Tie::IxHash; 

tie my %myhash, 'Tie::IxHash'; 

for (my $i=0; $i<20; $i++) { 
    $myhash{$i} = 2*$i; 
    } 

my @keys = keys %myhash; 
# @keys = (0,1,2,3,...) 
3

Tôi không tin rằng đây luôn là kỹ thuật tốt hơn, nhưng đôi khi tôi đã sử dụng nó. Thay vì chỉ có kiểu "băm", nó có thể lưu trữ cả số đếm và thứ tự nhận thấy.

Về cơ bản, thay vì $count{$line} có số lần được xem, $count{$line}{count} là thời gian được xem và $count{$line}{order} là thứ tự được xem.

my %count; 
while (my $line = <DATA>) { 
    chomp $line; 
    if ($line =~ /\S/) { 
     $count{$line} ||= { order => scalar(keys(%count)) }; 
     $count{$line}{count}++; 
    } 
} 

for my $line (sort { $count{$a}{order} <=> $count{$b}{order} } keys %count) { 
    print "$line $count{$line}{count}\n"; 
} 
4

Một tùy chọn khác là mô-đun perl đơn giản của David Golden's (@xdg) perl Hash::Ordered. Bạn đạt được thứ tự nhưng nó chậm hơn vì băm trở thành một đối tượng đằng sau hậu trường và bạn sử dụng các phương thức để truy cập và sửa đổi các phần tử băm. Có lẽ có những điểm chuẩn có thể định lượng mô-đun chậm hơn nhiều so với băm thông thường nhưng đó là cách hay để làm việc với cấu trúc dữ liệu khóa/giá trị trong các tập lệnh nhỏ và đủ nhanh cho tôi trong loại ứng dụng đó. Tài liệu cũng đề cập đến một số cách tiếp cận khác để đặt hàng một băm.

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