Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 在Perl中搜索版本号数组_Arrays_Perl_Search - Fatal编程技术网

Arrays 在Perl中搜索版本号数组

Arrays 在Perl中搜索版本号数组,arrays,perl,search,Arrays,Perl,Search,我有一个问题要解决,那就是从索引数组中找到目标版本的索引。索引数组如下所示:{16.3.1,16.2.5,16.1.4,15.3.5,15.1.1} 对于该数组中的每个单独项目,如16.3.1,它由以下三部分连接: 16是年度发布号。 3是季度发布号,其范围为{1,2,3,4}。 1是每两周发布一次的版本号,可以是以下6个选项之一:1、2、3、4、5、6。 数组按降序排序。 现在这些是要求: 如果我给出了一个目标版本,比如16.1.4,这个算法将返回该数组中的匹配索引,即2 如果我给出的是16.

我有一个问题要解决,那就是从索引数组中找到目标版本的索引。索引数组如下所示:{16.3.1,16.2.5,16.1.4,15.3.5,15.1.1}

对于该数组中的每个单独项目,如16.3.1,它由以下三部分连接:

16是年度发布号。 3是季度发布号,其范围为{1,2,3,4}。 1是每两周发布一次的版本号,可以是以下6个选项之一:1、2、3、4、5、6。 数组按降序排序。 现在这些是要求:

如果我给出了一个目标版本,比如16.1.4,这个算法将返回该数组中的匹配索引,即2

如果我给出的是16.1.5的目标版本,它不在该数组中,那么它将返回下一个可用版本的索引,也就是2

目标值始终高于15.1.1,这意味着它将始终返回有效索引

我正在考虑将这样一个值转换成一个数字,然后进行搜索。例如,16.1.4=>16*24+1*6+4=394


但我只是想知道是否有一种简单的方法可以解决这个问题?

Perl支持一种名为的数据类型,它将版本号打包为一个字符串,并带有一系列代码点。例如,v1.2.3将表示为字符串\x1\x2\x3

您可以使用v后跟点十进制序列来创建这样的字符串,或者任何带有两个或更多点的点十进制序列都将以相同的方式处理,即使没有v

因此,我们可以非常简单地解决您的问题,将版本字符串与来自的第一个索引函数结合使用,如下所示

use strict;
use warnings 'all';
use feature 'say';

use List::MoreUtils 'first_index';

my @versions = ( v16.3.1, v16.2.5, v16.1.4, v15.3.5, v15.1.1 );

for my $target ( v16.1.4, v16.1.5 ) {
  say first_index { $_ le $target } @versions;
}
use version;

for my $target ( "16.1.5", "16.1.4" ) {
    my $vs = version->parse($target);
    say first_index { $_ le $vs } @versions;
}
输出 首先,将版本字符串放入程序可能会有问题,这就是为什么我问您当前如何读取它们。但如果你解释一下你需要什么,那真的不是什么大问题

使现代化 我已将答案更改为使用v16.1.4、v16.1.5等。它以前工作得很好,但16.1.4与浮点值16.1完全不同,这一点并不明显。另一方面,v16.1.4和v16.1都是版本字符串

你也没有说你的输入来自哪里。公平地说,您可以声明一个版本的文本数组,正如我在回答中所说的,但是您的$target可能不会也是一个文本,否则首先编写程序就没有什么意义了

我希望您能谈谈这些东西是从哪里来的,以便我能帮助您,但您可能需要看看pragma,它提供了在普通字符串和版本字符串之间转换的类方法

例如,如果目标是作为字符串提供的,则可以使用version->parse将其转换为版本字符串,这意味着上面的最后一个循环如下所示

use strict;
use warnings 'all';
use feature 'say';

use List::MoreUtils 'first_index';

my @versions = ( v16.3.1, v16.2.5, v16.1.4, v15.3.5, v15.1.1 );

for my $target ( v16.1.4, v16.1.5 ) {
  say first_index { $_ le $target } @versions;
}
use version;

for my $target ( "16.1.5", "16.1.4" ) {
    my $vs = version->parse($target);
    say first_index { $_ le $vs } @versions;
}
所以version->parse16.1.4 eq v16.1.4总是正确的


我希望这已经澄清而不是混淆了

Perl支持一种名为的数据类型,它将版本号打包为带有一系列代码点的字符串。例如,v1.2.3将表示为字符串\x1\x2\x3

您可以使用v后跟点十进制序列来创建这样的字符串,或者任何带有两个或更多点的点十进制序列都将以相同的方式处理,即使没有v

因此,我们可以非常简单地解决您的问题,将版本字符串与来自的第一个索引函数结合使用,如下所示

use strict;
use warnings 'all';
use feature 'say';

use List::MoreUtils 'first_index';

my @versions = ( v16.3.1, v16.2.5, v16.1.4, v15.3.5, v15.1.1 );

for my $target ( v16.1.4, v16.1.5 ) {
  say first_index { $_ le $target } @versions;
}
use version;

for my $target ( "16.1.5", "16.1.4" ) {
    my $vs = version->parse($target);
    say first_index { $_ le $vs } @versions;
}
输出 首先,将版本字符串放入程序可能会有问题,这就是为什么我问您当前如何读取它们。但如果你解释一下你需要什么,那真的不是什么大问题

使现代化 我已将答案更改为使用v16.1.4、v16.1.5等。它以前工作得很好,但16.1.4与浮点值16.1完全不同,这一点并不明显。另一方面,v16.1.4和v16.1都是版本字符串

你也没有说你的输入来自哪里。公平地说,您可以声明一个版本的文本数组,正如我在回答中所说的,但是您的$target可能不会也是一个文本,否则首先编写程序就没有什么意义了

我希望您能谈谈这些东西是从哪里来的,以便我能帮助您,但您可能需要看看pragma,它提供了在普通字符串和版本字符串之间转换的类方法

例如,如果目标是作为字符串提供的,则可以使用version->parse将其转换为版本字符串,这意味着上面的最后一个循环如下所示

use strict;
use warnings 'all';
use feature 'say';

use List::MoreUtils 'first_index';

my @versions = ( v16.3.1, v16.2.5, v16.1.4, v15.3.5, v15.1.1 );

for my $target ( v16.1.4, v16.1.5 ) {
  say first_index { $_ le $target } @versions;
}
use version;

for my $target ( "16.1.5", "16.1.4" ) {
    my $vs = version->parse($target);
    say first_index { $_ le $vs } @versions;
}
所以version->parse16.1.4 eq v16.1.4总是正确的


我希望您的解决方案基本上具有以下形式:

use List::MoreUtils qw( first_index );

my @versions = qw( 16.3.1 16.2.5 16.1.4 15.3.5 15.1.1 );
my $target = '16.1.4';

my $target_key = make_key($target);
my $index = first_index { make_key($_) <= $target_key } @versions;

第一个解决方案是实现您建议的公式

第二种解决方案类似于version->parse,但没有所有的开销和特殊功能
您不需要的案例。

您的解决方案基本上具有以下形式:

use List::MoreUtils qw( first_index );

my @versions = qw( 16.3.1 16.2.5 16.1.4 15.3.5 15.1.1 );
my $target = '16.1.4';

my $target_key = make_key($target);
my $index = first_index { make_key($_) <= $target_key } @versions;

第一个解决方案是实现您建议的公式


第二种解决方案类似于version->parse,但没有您不需要的所有开销和特殊情况。

您的版本字符串看起来很正常,您的描述支持这样一种概念,即您可能只需进行字符串比较,而无需进一步转换。它们所代表的领域不太可能随意改变,例如,季度将始终是季度。因此,由于它们在关系上可以与字符串进行比较,简单的字符串比较可能就足够了

来自的binsearch_pos函数将提供目标元素的索引,或者如果未找到目标元素,则提供可以插入目标以保持顺序的索引。这是一个稳定的二进制搜索,因此它将始终返回目标匹配的最低索引。这些特征似乎正是您所需要的:

use List::BinarySearch qw(binsearch_pos);

my @array = qw(
    16.3.1
    16.2.5
    16.1.4
    15.3.5
    15.1.1
);

print "$_: $array[$_]\t" foreach 0 .. $#array;
print "\n\n";

print "$_: ", (binsearch_pos {$b cmp $a} $_, @array), "\n"
    foreach qw(16.3.1  16.3.6  16.2.7  16.2.5  16.2.4  15.1.1  15.1.3  15.1.0);
如果版本列表很短,那么list::MoreUtils::first_ix是一种简单的线性方法,将非常有效。如果列表足够大,二进制搜索可能值得考虑,因为它按对数而不是线性扩展。这意味着,随着版本字符串列表的增长,使用二进制搜索所需的搜索时间将比使用线性搜索的增长速度慢


因为您的列表是按降序排列的,所以此解决方案使用$b cmp$a,以适应降序排列。

您的版本字符串看起来很正常,您的描述支持这样一种概念,即您可能只需进行字符串比较,而无需进一步转换。它们所代表的领域不太可能随意改变,例如,季度将始终是季度。因此,由于它们在关系上可以与字符串进行比较,简单的字符串比较可能就足够了

来自的binsearch_pos函数将提供目标元素的索引,或者如果未找到目标元素,则提供可以插入目标以保持顺序的索引。这是一个稳定的二进制搜索,因此它将始终返回目标匹配的最低索引。这些特征似乎正是您所需要的:

use List::BinarySearch qw(binsearch_pos);

my @array = qw(
    16.3.1
    16.2.5
    16.1.4
    15.3.5
    15.1.1
);

print "$_: $array[$_]\t" foreach 0 .. $#array;
print "\n\n";

print "$_: ", (binsearch_pos {$b cmp $a} $_, @array), "\n"
    foreach qw(16.3.1  16.3.6  16.2.7  16.2.5  16.2.4  15.1.1  15.1.3  15.1.0);
如果版本列表很短,那么list::MoreUtils::first_ix是一种简单的线性方法,将非常有效。如果列表足够大,二进制搜索可能值得考虑,因为它按对数而不是线性扩展。这意味着,随着版本字符串列表的增长,使用二进制搜索所需的搜索时间将比使用线性搜索的增长速度慢


因为您的列表是按降序排列的,所以此解决方案使用$b cmp$a,它适应降序排列。

因此,如果您正在搜索版本6.1.5,是否希望查找早期版本6.1.4,而不是等于或大于6.1.5或更高版本的最低版本?这很不寻常。它们总是有三个字段还是16.1可能?。如何将这些数据读入Perl程序?是的,如果目标是16.1.5,并且它不包含在该数组中,我们将返回16.1.4的索引,并且该数组中没有16.1的项。原始数据只是一个字符串数组。因此,如果您正在搜索版本6.1.5,是否希望查找早期版本6.1.4,而不是等于或大于6.1.5或更高版本的最低版本?这很不寻常。它们总是有三个字段还是16.1可能?。如何将这些数据读入Perl程序?是的,如果目标是16.1.5,并且它不包含在该数组中,我们将返回16.1.4的索引,并且该数组中没有16.1的项。原始数据只是一个字符串数组。非常感谢,这看起来比我实现的要好得多!非常感谢,这看起来比我实现的要好得多+我对vstrings过敏。这个答案,推荐对短列表使用first_索引,对长列表使用二进制搜索,是正确的。但是,鉴于OP的字符串在字符串比较下的顺序良好,我认为没有必要执行额外的make_键步骤。数值比较的速度优势是否会被函数调用所淹没?我没有检查。@SinanÜnür,是的,这些解决方案之间的速度差异并没有那么大,这就是为什么我发布了所有这些解决方案。这里最好的优化是我已经建议过的一个:使用二进制搜索长列表的版本。如果有1000个版本,您最多需要执行10次检查才能找到所需的版本,而使用first_索引可能需要多达1000次检查。+1我对vString过敏。这个答案,推荐对短列表使用first_索引,对长列表使用二进制搜索,是正确的。然而,考虑到OP的字符串在字符串比较下是有序的,我不认为额外的make_键步骤I
这是必要的。数值比较的速度优势是否会被函数调用所淹没?我没有检查。@SinanÜnür,是的,这些解决方案之间的速度差异并没有那么大,这就是为什么我发布了所有这些解决方案。这里最好的优化是我已经建议过的一个:使用二进制搜索长列表的版本。如果有1000个版本,您最多需要执行10次检查才能找到所需的版本,而使用first_索引可能需要多达1000次检查。如果版本的格式始终为xx.x.x,则此操作有效。但如果其中一些是x.x.x,它就失败了。这就是为什么其他两个解决方案构成一个键。我同意,但样本数据似乎表明了两位数的年份。如果有可能追溯到0x年,那么sprintf%02u%1u%1u,shift将提供一个规范化字符串,尽管如果需要规范化,我也同意整数打包将更快,这就是为什么我对您的答案投了更高的票。如果版本始终是xx.x.x形式,这是可行的。但如果其中一些是x.x.x,它就失败了。这就是为什么其他两个解决方案构成一个键。我同意,但样本数据似乎表明了两位数的年份。如果有可能追溯到0x年,那么sprintf%02u%1u%1u,shift将提供一个规范化字符串,尽管如果需要规范化,我也同意您的整数打包将更快,这就是为什么我对您的答案投了赞成票。