Forループ - 配列名にイテレータを含む配列に追加する

Forループ - 配列名にイテレータを含む配列に追加する

次のような問題があります。いくつかの値を持つ配列がありますarr。各値を、異なる(すでに宣言されている)配列のセットearr$jarr[0]つまりearr1arr[1]earr2、そして一般的にarr[j-1]はに分類したいと考えearr$jています。(後で、同様の の要素を、arr対象の の次の要素として追加しますearr$j)。次のコード スニペット(より大きなコードの一部)を使用してこれを実行してみました。

for j in $(seq 1 $number_of_elements); do earr$j+=(${arr[j-1]}); done

2D 配列 (Bash ではサポートされていません) を作成しようとしているように思われると言われました (私の投稿「https://unix.stackexchange.com/questions/675454/for-loop-and-appending-over-list-of-arrays」を参照)。Bash 構文の不適切な使用の結果が何を示唆するかに関係なく、これは私の意図ではないことを強調します。以前の投稿では問題が適切に説明されていなかったため、これを再投稿します。

答え1

質問に文字通り答えると、ここでは、それは通常、次のような仕事ですeval

for i in "${!arr[@]}"; do
  eval '
    earr'"$i"'+=( "${arr[i]}" )
  '
done

eval危険ではありますが、正しく使用すれば安全です。間違いのリスクを抑えるには、展開が絶対に必要な部分を除いてすべてを一重引用符で囲み、一重引用符で囲まれていない部分 (ここでは$i二重引用符で囲まれており、変数の内容に展開されますi) が完全に制御されていることを確認するのが良い方法です。この場合、数字のみが含まれることがわかっているので、シェル コードとして評価される$iランダム データではありません(一重引用符から外したくない部分と比較してください)。eval${arr[i]}

2D 配列が適切ではないと言う理由がまだわかりません。ksh93(bash構文の大部分は ksh93 からコピーしましたが、多次元配列はコピーしていません) では、次のようにします。

for i in "${!arr[@]}"; do
  earr[i]+=( "${arr[i]}" )
done

perlいずれにせよ、シェルを使用する必要がある特別な理由がない限り、やなどの適切なプログラミング言語を使用する方がよいと思われるという @cas の意見に同意しますpython

答え2

以下は、Perl と Hash-of-Array-of-Arrays (HoAoA) データ構造を使用して、説明した内容を実行する方法の例です。

これを理解するには、次のマニュアル ページが役立ちます: perldata(perl データ型)、 perldsc(データ構造)、perllol(lol = リストのリスト)、perlref(リファレンス)、 (リファレンスのチュートリアル)。また、コマンド (例:またはperlreftut) を使用して、特定の perl 関数の詳細を取得することもできます。perldocperldoc -f opendirperldoc -f grep

スクリプトで使用されているsortと は組み込みのPerl関数であることに注意してください。これらはgrepないおよびコマンドライン ツール...必要に応じて、これらを Perl から呼び出すことができます (バックティックまたは引用符、または 関数sort、またはパイプを開く 関数、およびその他のいくつかの方法を使用)。これらすべてとその他の詳細については を使用してください。grepqxsystem()open()perldoc

$ cat HoAoA.pl 
#!/usr/bin/perl

use strict;
use Data::Dump qw(dd);

# $h is a ref to Hash-of-Array-ofArrays (HoAoA).
#
# This will be a data structure with the directory names
# (Folder1, Folder2, Folder3) as the hash keys of the top-level
# hash.  Each element of that hash will be an array where the
# indexes are the line numbers of the data.txt files in each
# of those directories. The data in these second-level arrays
# will be an array containing the three values in each line of
# data.txt: $$h{directory}[line number][element]
my $h;

# get the directory name from the first command line arg, default to ./
my $dir = shift // './';

# get a list of subdirectories that contain 'data.txt',
# excluding . and ..
opendir(my $dh, "$dir") || die "Couldn't open directory $dir: $!\n";
my @dirs = sort grep { $_ !~ /^\.+$/ && -d $_ && -f "$_/data.txt" } readdir($dh);
closedir($dh);

dd \@dirs;   # Data::Dump's dd function is great for showing what's in an array
print "\n";

foreach my $d (@dirs) {
  my $f = "$d/data.txt";
  open(my $fh,"<",$f) || die "Couldn't open file $f: $!\n";
  my $lc=0;  # line counter
  while(<$fh>) {
    chomp;   # strip trailing newline char at end-of-line
    my @row = split /\s*,\s*/;   # assume simple comma-delimited values
    push @{ $$h{$d}[$lc++] }, @row;
  }
  close($fh);
}

# dd is even better for showing complex structured data
dd $h;
print "\n";

# show how to access individual elements, e.g. by changing the
# zeroth element of line 0 of 'Folder1' to 999.
$$h{'Folder1'}[0][0] = 999;

dd $h;
print "\n";

# show how to print the data without using Data::Dump
# a loop like this can also be used to process the data.
# You could also process the data in the main loop above
# as the data is being read in.
foreach my $d (sort keys %{ $h }) {   # `foreach my $d (@dirs)` would work too
  print "$d/data.txt:\n";
  foreach my $lc (keys @{ $$h{$d} }) {
    print "  line $lc: ", join("\t",@{ $$h{$d}[$lc] }), "\n";
  }
  print "\n";
}

注: 上記は、単純なカンマ区切りのデータファイルを処理するために書かれています。実際のCSVでは、その癖や複雑さ(カンマが埋め込まれた複数行の二重引用符で囲まれたフィールドなど)があるため、テキスト::CSVモジュール。これは、コア Perl ディストリビューションに含まれていないサードパーティのライブラリ モジュールです。Debian および関連ディストリビューションでは、 を使用してこれをインストールできますapt-get install libtext-csv-perl libtext-csv-xs-perl。他のディストリビューションでも、おそらく同様のパッケージ名が付けられています。または、 (Perl コアに含まれるライブラリ モジュールをインストールおよび管理するツール) を使用してインストールすることもできますcpan

また、上記のスクリプトでは、データ::ダンプこれは、構造化データをダンプするのに便利なサードパーティのモジュールです。残念ながら、これは perl コア ライブラリの一部としては含まれていません。Debian などではapt-get install libdata-dump-perl、他のディストリビューションでも同様のパッケージ名が付けられます。また、最後の手段として、 でインストールすることもできますcpan

とにかく、次のフォルダー構造と data.txt ファイルを使用します。

$ tail */data.txt
==> Folder1/data.txt <==
1,2,3
4,5,6
7,8,9

==> Folder2/data.txt <==
7,8,9
4,5,6
1,2,3

==> Folder3/data.txt <==
9,8,7
6,5,4
3,2,1

HoHoA.pl スクリプトを実行すると、次の出力が生成されます。

$ ./HoAoA.pl 
["Folder1", "Folder2", "Folder3"]

{
  Folder1 => [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
  Folder2 => [[7, 8, 9], [4, 5, 6], [1, 2, 3]],
  Folder3 => [[9, 8, 7], [6, 5, 4], [3, 2, 1]],
}

{
  Folder1 => [[999, 2, 3], [4, 5, 6], [7, 8, 9]],
  Folder2 => [[7, 8, 9], [4, 5, 6], [1, 2, 3]],
  Folder3 => [[9, 8, 7], [6, 5, 4], [3, 2, 1]],
}

Folder1/data.txt:
  line 0: 999   2       3
  line 1: 4     5       6
  line 2: 7     8       9

Folder2/data.txt:
  line 0: 7     8       9
  line 1: 4     5       6
  line 2: 1     2       3

Folder3/data.txt:
  line 0: 9     8       7
  line 1: 6     5       4
  line 2: 3     2       1

関連情報