Как я читаю два объекта за один раз в цикле foreach Perl?

В этом случае я бы предложил использовать 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]]
 })
35
задан Zano 30 April 2013 в 10:53
поделиться

12 ответов

Я верю надлежащему способу сделать, это должно использовать 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;
    }
}
38
ответ дан Christopher Bottoms 27 November 2019 в 06:26
поделиться

вот реализация 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";
}
0
ответ дан runrig 27 November 2019 в 06:26
поделиться

Используя для цикла сделал бы то, в чем Вы нуждаетесь.

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";
}

редактирование : Я исправил свое сообщение для использования скалярной функции, чтобы получить размер массива и также добавить некоторую проверку в случае, если массив не содержит четное число элементов.

1
ответ дан Pierre-Luc Simard 27 November 2019 в 06:26
поделиться

Как 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;
  }
}
2
ответ дан Telemachus 27 November 2019 в 06:26
поделиться

Вы, вероятно, захотите создать простую подпрограмму, чтобы заставить его работать на Вас.

я предлагаю это:

{
  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";
}

Это является неразрушающим.

4
ответ дан user54650 27 November 2019 в 06:26
поделиться

Если я только мог бы использовать стандартный Perl без модулей, я был бы, вероятно, выпадающий к C-стилю для цикла, который рассчитывает 2:

for( my $i = 0; $i < @array; $i += 2 ) {
    my( $i, $j ) = @array[ $i, $i+1 ];
    ...
    }

Однако, если Вы хотели что-то воображение от одного из модулей, Вы не можете использовать, можно просто добавить что модуль к коду. Если можно написать код, можно использовать модули. Вам, возможно, просто придется включать модуль со всем кодом, который Вы поставляете, в то время как Вы устанавливаете @INC соответственно. Это - основная идея о inc:: Модуль:: Установка и ПАРИТЕТ .

я провожу много своего времени, работая с системой сборки, которая создает ее собственный репозиторий CPAN, устанавливает ее зависимости от его частного CPAN и затем тестирует код. Наличие фермы сборки не устраняет использовать модули; это - локальная политика, которая делает. Однако это не могло бы иметь смысла во всех случаях даже при том, что это возможно.

7
ответ дан brian d foy 27 November 2019 в 06:26
поделиться

Самый близкий эквивалент, к сожалению, идет олдскульный:

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";
}
10
ответ дан chaos 27 November 2019 в 06:26
поделиться

Настройте некоторые данные тестирования и импортируйте 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";
      }
    }

Цикличное выполнение по парам с помощью [1 111] List::Pairwise     (pair) .

    use List::Pairwise qw'pair';

    for my $pair (pair @array){
      my($a,$b) = @$pair;

      say "$a => $b";
    }

Цикличное выполнение по массиву 2 за один раз, с помощью [1 113] 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";
      }
    }
16
ответ дан Sinan Ünür 27 November 2019 в 06:26
поделиться

Я думаю, что Вы хотели бы сделать это по-другому. Попробуйте это:

while (scalar(@list) > 0) {
    $i = shift(@list);
    $j = shift(@list);
    print "i: $i, j:$j\n";
} 

Имеют в виду, что это уничтожит список, но он будет работать на тот небольшой цикл.

16
ответ дан Jack M. 27 November 2019 в 06:26
поделиться

Я использовал бы соединение встык.

my @list = qw(1 2 3 4 5 6);
while(my ($i,$j) = splice(@list,0,2)) {
  print "i: $i, j: $j\n";
}
20
ответ дан Andrew Barnett 27 November 2019 в 06:26
поделиться

Я придумал этот код для решения подобного требования:

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 для предложения.

0
ответ дан daotoad 27 November 2019 в 06:26
поделиться

Как насчет функционального решения общего назначения.

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 для цикла.

3
ответ дан 27 November 2019 в 06:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: