【发布时间】:2018-04-16 20:16:38
【问题描述】:
假设我的 IPvN 是一个与 IPv4 格式几乎相同的序列,唯一的区别是可以有任意数量的点或数字。我想对这些序列的列表进行如下排序。
- IPv4 在 IPv5 之前,依此类推。
- 对于相同的小数位数,从左到右在相同垂直位置的数字升序排序。
8.8.8.8
20.0.0.0
1.2.3.4.5
问题
1。如何让它更智能?
我使用了一种粗略的方式来合成逻辑条件表达式。我知道这样做是非常低效和浪费内存的,特别是当只有少数异常长的 IPvN 时,人类一眼就能解决,但我拖着完全冗余和无用的代码尾巴,例如 ... or $a->[1000] <=> $b->[1000]。
2。如何在单个"Schwartzian transform"中实现满足多个条件的排序?
正如你在下面看到的,我做了一个双层的叠加 Schwartzian 变换。
3。为什么会出现这个错误?
(我输出的第一行。)
Use of uninitialized value in numeric comparison (<=>) at (eval 4) line 1.
但是,如果是 '8.8.8.6.0' => 6 而不是 %IP_counter 中的 '8.8.8.8.0' => 6,则不会出现警告。
我只知道这个错误与'8.8.8.8' => 3有关。
我的垃圾代码
use strict;
use warnings;
use feature 'say';
use List::Util qw(max);
my %IP_counter =
(
'1.1.1.1.1' => 1,
'127.0.0.1' => 2,
'8.8.8.8' => 3,
'20.0.0.1' => 4,
'999999999999999999999999999999999999999999999999.9'
=> 5,
'8.8.8.8.0' => 6,
'888888888888888888888888888888888888888888888888.8'
=> 7,
);
# Find the max length
# Abbr. "c_n_d_m" -> "count numbers divided (max)".
my @c_n_d;
my $c_n_d_m = 0;
foreach (keys %IP_counter) {
@c_n_d = split /\./, $_;
$c_n_d_m = @c_n_d if $c_n_d_m < @c_n_d
}
# ?Q1. Question 1 arises here
# Concatenation of hardcode
my @m = (1..$c_n_d_m);
my $cond;
foreach my $i (0..@m-1) {$cond .= '$a->['.$m[$i].'] <=> $b->['.$m[$i].'] or '}
$cond = substr $cond, 0, rindex($cond, ' or ');
# ?Q2. Question 2 arises here
# Sort keys by numeral
# Do a double "Schwartzian transform"
my @sort_by_num =
# Sort by number of dots:
map { $_ }
sort { (split /\./, $a) <=> (split /\./, $b) }
map { [ $_, /(\d+)/g ] -> [@_] }
# Sort by (regarded as) shift floats:
map { $_->[0] }
sort { eval $cond }
map { [ $_, /(\d+)/g ] }
keys %IP_counter;
# Print the result
my $width = max map {length $_} keys %IP_counter;
foreach my $IP (@sort_by_num) {
printf "%-*s => $IP_counter{$IP}\n", $width, $IP
}
输出
Use of uninitialized value in numeric comparison (<=>) at (eval 4) line 1.
888888888888888888888888888888888888888888888888.8 => 7
999999999999999999999999999999999999999999999999.9 => 5
8.8.8.8 => 3
20.0.0.1 => 4
127.0.0.1 => 2
1.1.1.1.1 => 1
8.8.8.8.0 => 6
【问题讨论】:
-
你真的需要表示 1E48 这样大的数字吗?如果是这样,那么您最初的问题非常具有误导性,您的价值观实际上与 IP 地址无关。
-
@Borodin 好吧,我不得不承认数字不会那么夸张:) 所以我终于完全重新接受了 melpomene 的回答。
-
那么这些值的实际上限是多少?解决方案高度依赖此限制。
-
@Borodin 你的需求已经完全满意了~