В этом случае я бы предложил использовать mapply
вместо
mapply(function(x, y) {names(x)[2] <- y; x}, templist, allobj)
#[[1]]
# fruit df1 price
#1 apple Japan 32
#2 Orange China 53
#3 Pear Nigeria 12
#[[2]]
# grocery df2 name favourite.food invoice
#1 Durian Korea Mark Apple XD1
#2 Apple Japan John ORANGE XD2
#3 Watermelon Malaysia Tammy Cakes XD3
#[[3]]
# address df3
#1 address1 USA
#2 address2 UK
#3 address3 China
Если вы хотите использовать lapply
, вы можете использовать x
в качестве индекса для поднабора обоих [115 ], а также allobj
, поскольку для 1-го списка нам нужно имя из 1-го значения allobj
, для 2-го списка мы хотим 2-е значение allobj
и т. д.
lapply(seq_along(templist), function(x) {
names(templist[[x]])[2] <- allobj[x]
templist[[x]]
})
Я верю надлежащему способу сделать, это должно использовать natatime, от Список:: MoreUtils:
из документов:
natatime ЧЕРНЫЙ СПИСОК
Создает итератор массива для цикличного выполнения по массиву в блоках
$n
объекты за один раз. (n
за один раз, получите его?). Примером является, вероятно, лучшее объяснение, чем я мог дать в словах.
Пример:
my @x = ('a' .. 'g');
my $it = natatime 3, @x;
while (my @vals = $it->())
{
print "@vals\n";
}
Это печатает
a b c d e f g
реализация List::MoreUtils::natatime
:
sub natatime ($@)
{
my $n = shift;
my @list = @_;
return sub
{
return splice @list, 0, $n;
}
}
вот реализация natatime, который не делает копию списка:
sub natatime {
my $n = shift;
my $list = \@_;
sub {
return splice @$list, 0, $n;
}
}
my $it = natatime(3, qw(1 2 3 4 5 6));
while ( my @list = $it->() ) {
print "@list\n";
}
Используя для цикла сделал бы то, в чем Вы нуждаетесь.
use strict;
use warnings;
my @list = qw(1 2 3 4 5 );
my $i = 0;
for ($i = 0; $i < scalar(@list); $i++)
{
my $a = $list[$i];
my $b = $list[++$i];
if(defined($a)) {
print "a:$a";
}
if(defined($b)) {
print "b:$b";
}
print "\n";
}
редактирование : Я исправил свое сообщение для использования скалярной функции, чтобы получить размер массива и также добавить некоторую проверку в случае, если массив не содержит четное число элементов.
Как Mirod объясняет, нет большого количества кода к нему. Вот в значительной степени все, в чем Вы нуждались бы. (Обратите внимание, что у меня нет проверок на нечетные списки и т.п.)
#!/usr/bin/env perl
use strict;
use warnings;
my @list = qw/1 2 3 4 5 6/;
my $get_em = get_by(2, @list);
while ( my ($i, $j) = $get_em->() ) {
print "i: $i, j: $j\n";
}
sub get_by {
my $n = shift;
my @list = @_;
return sub {
return splice @list, 0, $n;
}
}
Вы, вероятно, захотите создать простую подпрограмму, чтобы заставить его работать на Вас.
я предлагаю это:
{
my $cl_ind = 0;
sub arrayeach(@) {
my @obj = @_;
if(($cl_ind+2) > @obj)
{
$cl_ind = 0;
return;
}
$cl_ind+=2;
return ($obj[$cl_ind-2],$obj[$cl_ind-1]);
}
}
закрытие заставляет его работать чисто. Для использования arrayeach (который работает как хеш каждый, не требуя опасного приведения к массиву:
my @temp = (1,2,3,4,5,6,1,2,3,4,5,6);
while( ($a,$b) = arrayeach(@temp)) {
print "A $a AND $b\n";
}
Это является неразрушающим.
Если я только мог бы использовать стандартный Perl без модулей, я был бы, вероятно, выпадающий к C-стилю для цикла, который рассчитывает 2:
for( my $i = 0; $i < @array; $i += 2 ) { my( $i, $j ) = @array[ $i, $i+1 ]; ... }
Однако, если Вы хотели что-то воображение от одного из модулей, Вы не можете использовать, можно просто добавить что модуль к коду. Если можно написать код, можно использовать модули. Вам, возможно, просто придется включать модуль со всем кодом, который Вы поставляете, в то время как Вы устанавливаете @INC
соответственно. Это - основная идея о inc:: Модуль:: Установка и ПАРИТЕТ .
я провожу много своего времени, работая с системой сборки, которая создает ее собственный репозиторий CPAN, устанавливает ее зависимости от его частного CPAN и затем тестирует код. Наличие фермы сборки не устраняет использовать модули; это - локальная политика, которая делает. Однако это не могло бы иметь смысла во всех случаях даже при том, что это возможно.
Самый близкий эквивалент, к сожалению, идет олдскульный:
for(my $ix = 0; $ix <= $#list; $ix += 2) {
my $i = $list[$ix];
my $j = $list[$ix + 1];
print "i: $i, j:$j\n";
}
мне нравится ответ M Jack лучше, действительно, хотя я записал бы это в более сексуальном Perl:
while(@list) {
my $i = shift @list;
my $j = shift @list;
print "i: $i, j:$j\n";
}
say
: use Modern::Perl;
use List::AllUtils qw'zip';
my @array = zip @{['a'..'z']}, @{[1..26]} ;
{
my $i = 0;
while(
(my($a,$b) = @array[$i++,$i++]),
$i <= @array # boolean test
){
say "$a => $b";
}
}
List::Pairwise
(pair)
. use List::Pairwise qw'pair';
for my $pair (pair @array){
my($a,$b) = @$pair;
say "$a => $b";
}
List::MoreUtils
(natatime)
. use List::AllUtils qw'natatime';
my $iter = natatime 2, @array;
while( my($a,$b) = $iter->() ){
say "$a => $b";
}
{
my %map = @array;
for my $key (keys %map){
my $value = $map{$key};
say "$key => $value";
}
}
Я думаю, что Вы хотели бы сделать это по-другому. Попробуйте это:
while (scalar(@list) > 0) {
$i = shift(@list);
$j = shift(@list);
print "i: $i, j:$j\n";
}
Имеют в виду, что это уничтожит список, но он будет работать на тот небольшой цикл.
Я использовал бы соединение встык.
my @list = qw(1 2 3 4 5 6);
while(my ($i,$j) = splice(@list,0,2)) {
print "i: $i, j: $j\n";
}
Я придумал этот код для решения подобного требования:
sub map_pairs(&\@) {
my $op = shift;
use vars '@array';
local *array = shift; # make alias of calling array
return () unless @array;
# Get package global $a, $b for the calling scope
my ($caller_a, $caller_b) = do {
my $pkg = caller();
no strict 'refs';
\*{$pkg.'::a'}, \*{$pkg.'::b'};
};
# Get index counter size.
my $limit = $#array/2;
# Localize caller's $a and $b
local(*$caller_a, *$caller_b);
# This map is also the return value
map {
# assign to $a, $b as refs to caller's array elements
(*$caller_a, *$caller_b) = \($array[$_], $array[$_+1]);
$op->(); # perform the transformation
}
map { 2 * $_ } 0..$limit; # get indexes to operate upon.
}
Вы используете его как так:
@foo = qw( a 1 b 2 c 3 );
my @bar = map_pairs { "$a is $b" } @foo;
добираться:
@bar = ( 'a is 1', 'b is 2', 'c is 3' );
Я означал отправлять специалисту по обслуживанию Списка:: MoreUtils, но у меня нет версии XS для предложения.
Как насчет функционального решения общего назначения.
use Carp; # so mapn can croak about errors
sub mapn (&$@) {
my ($sub, $n, @ret) = splice @_, 0, 2;
croak '$_[1] must be >= 1' unless $n >= 1;
while (@_) {
local *_ = \$_[0];
push @ret, $sub->(splice @_, 0, $n)
}
@ret
}
sub by ($@) {mapn {[@_]} shift, @_}
sub every ($@); *every = \&by;
Функция mapn
работает так же, как map
, за исключением первого аргумента после его block - количество элементов, которые нужно взять. Он помещает первый элемент в $ _
и все элементы в @_
.
print mapn {"@_\n"} 2 => 1 .. 5;
# prints
1 2
3 4
5
Следующие два идентичных подпрограммы, от
и каждый
создают полезные наречия для различных конструкций цикла. Они обрабатывают список с помощью mapn и возвращают список ссылок на массивы желаемого размера
print "@$_\n" for every 2 => 1..10;
print map {"@$_\n"} grep {$_->[1] > 5} by 2 => 1..10;
Я считаю, что это более чистое и интуитивно понятное решение, чем natatime или другие одноразовые решения, такие как стиль AC для цикла.