【问题标题】:How to replicate and/or reassign array elements in a multi-dimensional array?如何复制和/或重新分配多维数组中的数组元素?
【发布时间】:2018-10-23 13:19:53
【问题描述】:

代码在循环中的某处变得混乱!请帮我解决。

详情

使用引用元素复制和/或重新分配多维数组中的大部分数组元素。

  • File-1:数组索引和元素列表,需要在原始数组中维护。

  • File-2:需要用上述信息重写的原始多维数组。除上述元素外,其余所有元素都必须重新分配。

  • File-3:预期输出(重新分配的数组元素)

注意:除了来自 file1 的数组索引外,其余所有索引都将替换为参考线。参考线通常出现在阵列的第一行。
在修改后的数组中,不需要参考线。

文件-1:

ID1    2    E1,E4
ID2    5    E6,E7,E9
ID3    1    E3

文件 2:

ID1.txt

Ref K L M N O P A B C D
E1 S H G U S K R E K K
E2 S L G N O P A B C D
E3 S L G N O P A B C D
E4 U L G G O P A B C D
E5 U L M G O P A J C D
E6 U L M G O P A J C D
E7 U L M G O P A J C D
E8 U L M G O P A J C D
E9 S L M N O P A J C D
E10 S L M N O P A J C D
.
.
.

文件 3:预期输出

new_ID1.txt

E1    K L G N O P A B C D
E2    K L M N O P A B C D
E3    K L M N O P A B C D
E4    K L G N O P A B C D
E5    K L M N O P A B C D
E6    K L M N O P A B C D
E7    K L M N O P A B C D
E8    K L M N O P A B C D
E9    K L M N O P A B C D
E10    K L M N O P A B C D
.
.
.

在预期的输出 (new_ID1.txt) 中,“E1”和“E4”的数组的第二个索引是从原始数组中维护的。其他所有内容都替换为“E2,E3,E5...”中的参考线。

代码

#!/usr/bin/perl 

use strict;
use warnings;

my %HoHoA = ();

open(IN,"ids.txt");
my @ids = <IN>; chomp @ids; close IN;

open(IN2,"indices_and_values.txt");

while(my $l = <IN2>)
{
    chomp $l;
my @tmp = split "\t", $l;
my $lid = $tmp[0];
my $pos = $tmp[1];
my @gps = @tmp[2..$#tmp];

    foreach my $g (@gps)
    {
        push @{$HoHoA{$lid}{$g}}, $pos;
    }
}
close IN2;


foreach my $outer (sort keys %HoHoA)
{
open(IN3,"$outer.txt");
my @rS = <IN3>; chomp @rS; close IN3;

    my @orgArr = (); my @refArr = (); my @newArr = ();
    foreach my $unk (@rS) 
    { 
        @orgArr = split "\t", $unk;
        if($unk =~ /^Ref/)
        { 
            @refArr = split "\t", $unk;
            next;
        }
    foreach my $inner (sort keys %{$HoHoA{$outer}})
    {
        if($inner =~ /^$orgArr[0]/)
        {
            foreach my $ele (sort {$a <=> $b} @{$HoHoA{$outer}{$inner}})
            {
                $refArr[$ele] = $orgArr[$ele];
            }
        }
        #else
        #{
        #}
    }
    print ">$orgArr[0]\t";
    print join("\t",@refArr[1..$#refArr]);
    print "\n";
}
    @rS = ();
    print "\n";

}

【问题讨论】:

  • 我不明白。它说 E1 被保留(至少是“第二个索引”...)但是 ID1.txt 文件中的 E1 行是 S H G U... 而在所需的输出文件中是 K L G N... -- - 完全不同。 “数组 E1”是什么意思——以 E1 开头的行?
  • @zdim 只有文件 1 中的给定数组索引必须保留,而不是整个元素。例如,应保持 E1[2]。 E1[2] 是“G”。其他所有元素都应替换为 Ref 元素(数组的第一行)。所以它是 K L G N O P A B C D。我(假设)提到了数组 E1、E2 等,因为多行(行/列)。了解另一种方式也会有所帮助。 File-1格式如下,“id index_value数组”
  • 啊,谢谢您——是的,它在问题中说明了所有内容。如果我仍然误解了什么,请告诉我(见答案)

标签: perl multidimensional-array replicate


【解决方案1】:

显示的代码是善意的,但有点太复杂了;您可能在嵌套数据结构的操作中迷失了方向。这是另一种更简单的方法。

将“参考”文件 (File-1) 中的信息解析为哈希 (E1 =&gt; [2, ...], ..)。我将数据的索引保存在 arrayref 中,以允许一行有多个索引。然后逐行进行,将这些索引处的数据替换为具有键的行,并随时打印输出。

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

my ($ref_file, $data_file) = @ARGV;
die "Usage: $0 ref-file data-file\n" if not $ref_file or not $data_file;

open my $fh, '<', $ref_file or die "Can't open $ref_file: $!";
my %rows;
while (<$fh>) {
    my (undef, $idx, $row_id) = split;
    for (split /,/, $row_id) {
        push @{$rows{$_}}, $idx;        # elem => [ indices ]
    }
}

my $outfile = 'new_' . $data_file;
open    $fh,     '<', $data_file  or die "Can't open $data_file: $!";
open my $fh_out, '>', $outfile    or die "Can't open $outfile: $!";

my @ref = split ' ', <$fh>;
shift @ref;                  # toss the first field

while (<$fh>) {
    my ($row_id, @data) = split;

    if (exists $rows{$row_id}) {              # this row needs attention
        my @new_row = @ref;
        foreach my $idx (@{$rows{$row_id}}) { # keep data at these indices
            $new_row[$idx] = $data[$idx];
        }
        say $fh_out join "\t", $row_id, @new_row;
    }
    else {                                    # use whole reference line
        say $fh_out join "\t", $row_id, @ref;
    }
}

新文件(为了便于阅读,用两个空格代替实际的制表符显示)

E1 K L G N O P A B C D E2 K L M N O P A B C D E3 K L M N O P A B C D E4 K L G N O P A B C D E5 K L M N O P A B C D E6 K L M N O P A B C D E7 K L M N O P A B C D E8 K L M N O P A B C D E9 K L M N O P A B C D E10 K L M N O P A B C D

请注意,给定的输入文件恰好具有与参考线相同的条目,用于在许多感兴趣的索引处进行替换——因此我们在上述输出中看不到这些“变化”。 (我通过更改输入文件进行测试以便能够看到。)

【讨论】:

  • 不幸的是它仍然提供与输出相同的输入!
  • @perlbeginner 嗯?它打印如图所示的输出,这是您想要的问题输出...?它使用您在问题中提供的输入文件。正如解释的那样,我还测试了所有应该更改的字段,并且它正确地将数据保留在这些索引处(同时用该参考线替换所有其他字段)。
  • @perlbeginner 我不明白:复制粘贴程序并使用您在问题中显示的文件(File-1 和 ID1.txt)运行它 - 它必须打印显示的内容在答案中(我从控制台复制粘贴它,打印时使用两个空格而不是制表符)。这正是所需的输出。
  • 我复制粘贴并尝试完全相同。您在此处显示的输出是所需的输出。但是当我运行它时,它给出了类似于 file2 (ID1.txt) 而不是 new_ID1.txt
  • @perlbeginner 我刚刚检查过:我将上面的代码复制粘贴到一个新文件中,然后运行script.pl File-1 ID1.txt。它产生了new_ID1.txt,内容如上所示。你确定你检查的是正确的文件吗?您是否还有其他可能引起混淆的文件?
【解决方案2】:

如果我正确理解了您的问题陈述,这是一种方法:

#!/usr/bin/perl

use strict;
use warnings;

my %keep_idx;

open FILE, "file-1" or die "Couldn't open file-1";
while(<FILE>) {
    my (undef, $idx, $id_str) = split /\s+/;
    my @ids = split /,/, $id_str;
    foreach my $id (@ids) {
        $keep_idx{$id}{$idx} = 1;
    }
}
close FILE;

open FILE, "file-2" or die "Couldn't open file-2";
open OUTFILE, ">file-3" or die "Couldn't open file-3";
my (undef, @ref) = split /\s+/, <FILE>;
while(<FILE>) {
    my ($id, @src) = split /\s+/;
    my $line = "$id";
    for (my $i = 0; $i <= $#src; $i++) {
        my $e = $keep_idx{$id}{$i} ? $src[$i] : $ref[$i];
        $line .= " $e";
    }
    print OUTFILE "$line\n";
}
close OUTFILE;
close FILE;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-25
    • 2012-05-16
    相关资源
    最近更新 更多