按值排序 哈希值 哈希值 哈希值 Perl

发布于 2024-07-18 02:49:46 字数 820 浏览 5 评论 0原文

我有一个类似于以下的哈希结构:

KeyA => {
         Key1 => {
                   Key4 => 4
                   Key5 => 9
                   Key6 => 10
                 }
         Key2 => {
                   Key7 => 5
                   Key8 => 9
                 }
        }
KeyB => {
         Key3 => {
                   Key9 => 6
                   Key10 => 3
                 }
        }

我需要打印出通过哈希结构的遍历路径以及遍历结束时的值,这样这是按值排序的。 例如,对于上面的哈希结构,我需要打印:

KeyB Key3 Key10 3
KeyA Key1 Key4  4
KeyA Key2 Key7  5
KeyB Key3 Key9  6
KeyA Key2 Key8  9
KeyA Key1 Key5  9
KeyA Key1 Key6  10

目前,为了解决这个问题,我使用嵌套的 foreach 循环遍历哈希结构,并通过插入键等于遍历路径的元素(例如“KeyA Key3 Key10")和值等于遍历路径末尾的值(例如3),然后执行另一个foreach循环,按值对扁平散列进行排序。

有没有更有效的方法来做到这一点?

I have a hash structure similar to the following:

KeyA => {
         Key1 => {
                   Key4 => 4
                   Key5 => 9
                   Key6 => 10
                 }
         Key2 => {
                   Key7 => 5
                   Key8 => 9
                 }
        }
KeyB => {
         Key3 => {
                   Key9 => 6
                   Key10 => 3
                 }
        }

I need to print out the traversal path through the hash structure and the value at the end of the traversal, such that this is ordered by value.
For example, for the above hash structure I need to print:

KeyB Key3 Key10 3
KeyA Key1 Key4  4
KeyA Key2 Key7  5
KeyB Key3 Key9  6
KeyA Key2 Key8  9
KeyA Key1 Key5  9
KeyA Key1 Key6  10

Currently, to solve this I am traversing the hash structure using nested foreach loops, and creating a flattened hash by inserting an element with key equal to the traversal path (e.g. "KeyA Key3 Key10") and value equal to the value at the end of the traversal path (e.g. 3), then doing another foreach loop which sorts the flattened hash by value.

Is there a more efficient way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

作妖 2024-07-25 02:49:46

考虑创建一个排序数组,而不是创建一个新的哈希。 迭代初始值,根据值、键值对插入到数组中,然后迭代结果数组。 这将为您提供初始迭代的 O(n) + 每次插入的 O(lg n) + 最终迭代的 O(n)。

Instead of creating a new hash, consider creating a sorted array. Iterate over the initial values, inserting in to the array, according to the value, the key-value pair, then iterate over the resulting array. This should give you O(n) on the initial iteration + O(lg n) for each insertion + O(n) for the final iteration.

假扮的天使 2024-07-25 02:49:46

您还可以使用递归解决方案来解决任意嵌套深度的嵌套数据结构的此问题。 您递归地构建一个包含路径和值的目标数组,然后对该数组进行排序。

use warnings;
use strict;

sub paths {
    my ($data, $cur_path, $dest) = @_; 
    if (ref $data eq 'HASH') {
        foreach my $key (keys %$data) {
            paths($data->{$key}, [@$cur_path, $key], $dest);
        }   
    } else {
        push @$dest, [$cur_path, $data];
    }   
}

my $data = {
    KeyA => {
        Key1 => { Key4 => 4, Key5 => 9, Key6 => 10 },
        Key2 => { Key7 => 5, Key8 => 9 }
    },
    KeyB => { Key3 => { Key9 => 6, Key10 => 3 } }
};

my $dest = []; 
paths($data, [], $dest);

foreach my $result (sort { $a->[1] <=> $b->[1] } @$dest) {
    print join(' ', @{$result->[0]}, $result->[1]), "\n";
}

You can also solve this problem for a nested data structure of arbitrary nesting depth using a recursive solution. You recursively build up a destination array containing paths and values, and then sort that array.

use warnings;
use strict;

sub paths {
    my ($data, $cur_path, $dest) = @_; 
    if (ref $data eq 'HASH') {
        foreach my $key (keys %$data) {
            paths($data->{$key}, [@$cur_path, $key], $dest);
        }   
    } else {
        push @$dest, [$cur_path, $data];
    }   
}

my $data = {
    KeyA => {
        Key1 => { Key4 => 4, Key5 => 9, Key6 => 10 },
        Key2 => { Key7 => 5, Key8 => 9 }
    },
    KeyB => { Key3 => { Key9 => 6, Key10 => 3 } }
};

my $dest = []; 
paths($data, [], $dest);

foreach my $result (sort { $a->[1] <=> $b->[1] } @$dest) {
    print join(' ', @{$result->[0]}, $result->[1]), "\n";
}
秋日私语 2024-07-25 02:49:46

对于您给出的数据结构,实际上没有嵌套循环的替代方案。 (可能有更好的数据结构,但我们无法知道。)我会这样编码:

use strict;
use warnings;

my %hash = (
    KeyA => {
        Key1 => {
            Key4 => 4,
            Key5 => 9,
            Key6 => 10,
        },
        Key2 => {
            Key7 => 5,
            Key8 => 9,
        },
    },
    KeyB => {
        Key3 => {
            Key9 => 6,
            Key10 => 3,
        },
    },
);

my @array;
while (my ($k1, $v1) = each %hash) {
    while (my ($k2, $v2) = each %$v1) {
        while (my ($k3, $v3) = each %$v2) {
            push @array, [$k1, $k2, $k3, $v3];
        }
    }
}

foreach my $x (sort { $a->[-1] <=> $b->[-1] } @array) {
    print join(' ', @$x), "\n";
}

For the data structure you've given there's not really an alternative to nested looping. (There might be a better data structure, but there's no way for us to know.) I'd code it this way:

use strict;
use warnings;

my %hash = (
    KeyA => {
        Key1 => {
            Key4 => 4,
            Key5 => 9,
            Key6 => 10,
        },
        Key2 => {
            Key7 => 5,
            Key8 => 9,
        },
    },
    KeyB => {
        Key3 => {
            Key9 => 6,
            Key10 => 3,
        },
    },
);

my @array;
while (my ($k1, $v1) = each %hash) {
    while (my ($k2, $v2) = each %$v1) {
        while (my ($k3, $v3) = each %$v2) {
            push @array, [$k1, $k2, $k3, $v3];
        }
    }
}

foreach my $x (sort { $a->[-1] <=> $b->[-1] } @array) {
    print join(' ', @$x), "\n";
}
Hello爱情风 2024-07-25 02:49:46

使用多维哈希模拟将其转换为平面哈希(请参阅 perlvar 中的 $; ),然后对结果哈希进行排序。

use strict;
use warnings;
my %hash = (
    KeyA => {
          Key1 => {
                    Key4 => 4,
                    Key5 => 9,
                    Key6 => 10,
                  },
          Key2 => {
                    Key7 => 5,
                    Key8 => 9,
                  }
         },
    KeyB => {
          Key3 => {
                    Key9 => 6,
                    Key10 => 3,
                  },
         },
);

my %fhash = 
   map {
        my @fh;
        foreach my $k2 (keys %{$hash{$_}}) {
                foreach my $k3 (keys %{$hash{$_}{$k2}}) {
                        push @fh, (join($;, $_, $k2, $k3) => $hash{$_}{$k2}{$k3});
                }   
        }
        @fh;
   } keys %hash;



foreach (sort { $fhash{$a} <=> $fhash{$b} } keys %fhash) {
    printf("%s\t%d\n", join("\t", split(/$;/, $_)), $fhash{$_});
}

您可以将生成 fhash 的 map / foreach 循环直接传递给排序。

Convert it into a flat hash using multidimensional hash emulation (see $; in perlvar), then sort the resulting hash.

use strict;
use warnings;
my %hash = (
    KeyA => {
          Key1 => {
                    Key4 => 4,
                    Key5 => 9,
                    Key6 => 10,
                  },
          Key2 => {
                    Key7 => 5,
                    Key8 => 9,
                  }
         },
    KeyB => {
          Key3 => {
                    Key9 => 6,
                    Key10 => 3,
                  },
         },
);

my %fhash = 
   map {
        my @fh;
        foreach my $k2 (keys %{$hash{$_}}) {
                foreach my $k3 (keys %{$hash{$_}{$k2}}) {
                        push @fh, (join($;, $_, $k2, $k3) => $hash{$_}{$k2}{$k3});
                }   
        }
        @fh;
   } keys %hash;



foreach (sort { $fhash{$a} <=> $fhash{$b} } keys %fhash) {
    printf("%s\t%d\n", join("\t", split(/$;/, $_)), $fhash{$_});
}

You could pass the the map / foreach loop that generates fhash directly to the sort.

氛圍 2024-07-25 02:49:46

这些其他解决方案看起来更优雅,因为它们“聪明”。 但是,考虑到数据结构的简单性,您的方法实际上就很好了。 这种结构很容易被扁平化。 您要求更有效的解决方案,但没有提供。

These other solutions are seemingly more elegant because they're "clever". However, given the simplicity of your data structure, your method is actually just fine. That structure is easily flattened. You asked for a more efficient solution, none was provided.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文