Linux Bashrc Nexted For Loops - arrays

Below is my code, I have two arrays...array and array2.
#!/bin/bash
array = (1 3 5 7 9)
array2 = (2 4 6 8 A)
for i in "${array[#]}"
do
echo $i
for i in "${array2[#]}"
do
echo $i
done
done
I want to have the following output echoed out onto my console when I run my script:
1
2
3
4
5
6
7
8
9
A
But instead I get the following:
1
2
4
6
8
A
3
2
4
6
8
A
5
2
4
6
8
A
7
2
4
6
8
A
9
2
4
6
8
A
I'm really trying to accomplish the following through nested loops like in C/C++:
char array[5] = {1, 3, 5, 7, 9};
char array2[5] = {2, 4, 6, 8, A};
for (int i=0; i<5; i++){
std::cout << array[i] << std::endl;
std::cout << array2[i] << std::endl;
}
But how can I use the same iterator var i to control two different arrays?

Loop over the indices instead of the elements:
#!/bin/bash
array=(1 3 5 7 9)
array2=(2 4 6 8 A)
for i in "${!array[#]}"
do
echo "${array[i]}"
echo "${array2[i]}"
done

The more or less exact transcription of the c++ code would be
for i in {0..5}
do
echo ${array[$i]}
echo ${array2[$i]}
done

To add another algorithm, you can repeatedly print the first element of each array and pop them until the first is empty:
array=(1 3 5 7 9)
array2=(2 4 6 8 A)
while [ -n "$array" ]
do
echo ${array[0]}
echo ${array2[0]}
array=("${array[#]:1}")
array2=("${array2[#]:1}")
done
edit: This does destroy the arrays as you go, so only use it if you don't care about the arrays existing after the loop.

Related

How to use a nested for loop to create a 1D array of integer pairs on a range?

In bash, I am trying to create 1-D array that contains all possible integer pairs on a range from a low value to a high value (i.e. 1 to 2)
I've tried using a nested for loop, however the out put I get is the array of the correct size, but all values are the high value (in this case 2)
I've tried nested for loops, however the array I am creating is not the correct size nor does it contain the correct combinations.
for (( i=$low; i<=$high; i++ ))
do
range_array[i]=$i
done
range=${#range_array[#]}
range_squared=$(( $range*$range))
new_range=$(( 2*$range_squared))
for (( i = $low; i <= $high; i++ ));do
for (( j = 1; j <= $new_range; j++ )) do
combo_array[j]=$i
done
done
echo "the following is the combo array"
echo ${combo_array[#]}
I expect the combo_array to be:
1 1 1 2 2 1 2 2
instead it is
2 2 2 2 2 2 2 2
That's too much work for such a trivial task. Here is a simple and working one:
combo_array=()
for ((i=low; i<=high; ++i)); do
for ((j=low; j<=high; ++j)); do
combo_array+=("$i" "$j")
done
done
echo "${combo_array[#]}"
Given low=6 and high=9, it outputs
6 6 6 7 6 8 6 9 7 6 7 7 7 8 7 9 8 6 8 7 8 8 8 9 9 6 9 7 9 8 9 9

Loop a 2D array vertically and choose one from each line

How to loop a 2D array, such as
1 2 3 4
5 6 7 8
9 10 11 12
choose one from each line everytime, left first. The expected order for the example is:
1 5 9
2 5 9
1 6 9
1 5 10
2 6 9
2 5 10
1 6 10
2 6 10
....
Thanks.
you can try two for loops
$a[$row][$column];
for($i=0; $i <$row; i++) {
for($j=0; $j<$column;$j++){
echo $a[$j][$i];
}
}
you can indent after 1 loop

Print all possible combinations of an array of arrays

I want to take three files that each contain 80 or more lines of text and print all possible combinations of those three files.
For the sake of clarity, let's assume that
File1 contains
1
2
3
File2 contains
4
5
6
File3 contains
7
8
9
If I wanted to print only those combinations then there are many answers that I could use. However, as the files contain more lines that I care type manually into the Perl script. I am building an array from each file, then I build an array ref of those arrays. Finally I am attempting to use List::Permutor to print the combinations.
The problem I am getting is that I am printing out the memory references, and I cannot figure out how to dereference the arrays inside of the List::Permutor call.
Perl code
use List::Permutor;
use warnings;
open (FILE, app_txt);
chomp (#app = (<FILE>));
close (FILE);
open (FILE, att1_txt);
chomp (#att1 = (<FILE>));
close (FILE);
open (FILE, att2_txt);
chomp (#att2 = (<FILE>));
close (FILE);
my $permutor = List::Permutor->new( \#app, \#att1, \#att2);
while ( my #permutation = $permutor->next() ) {
print "#permutation\n";
}
I wrote Set::CrossProduct for this purpose.
It's not clear what you want.
Note that all the provided output of the snippets below are for the following inputs:
my #app = ( 1, 2, 3 );
my #att1 = ( 4, 5, 6 );
my #att2 = ( 7, 8, 9 );
If you want permutations of the arrays, your code works as-is.
use List::Permutor qw( );
my $permutor = List::Permutor->new( \#app, \#att1, \#att2);
while ( my #permutation = $permutor->next() ) {
say join ", ", map { "[#$_]" } #permutation;
}
Output:
[1 2 3], [4 5 6], [7 8 9]
[1 2 3], [7 8 9], [4 5 6]
[4 5 6], [1 2 3], [7 8 9]
[4 5 6], [7 8 9], [1 2 3]
[7 8 9], [1 2 3], [4 5 6]
[7 8 9], [4 5 6], [1 2 3]
If you want permutations of the contents of the arrays (regardless of the array from which a string originated), then you just need to create a list from the contents of the arrays.
use List::Permutor qw( );
my $permutor = List::Permutor->new( #app, #att1, #att2 );
while ( my #permutation = $permutor->next() ) {
say "#permutation";
}
Output:
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 9 8
1 2 3 4 5 6 8 7 9
1 2 3 4 5 6 8 9 7
1 2 3 4 5 6 9 7 8
1 2 3 4 5 6 9 8 7
1 2 3 4 5 7 6 8 9
1 2 3 4 5 7 6 9 8
1 2 3 4 5 7 8 6 9
1 2 3 4 5 7 8 9 6
...
9 8 7 6 5 4 3 2 1
Keep in mind that P(80) is 100,000,000,000,000,000,000,000,000,000,000,000,000 times the number of atoms in the observable universe.
If you want all possible sets of a single element from each array, then you can use the following:
for my $app (#app) {
for my $att1 (#att1) {
for my $att2 (#att2) {
say "$app $att1 $att2";
}}}
or
use Algorithm::Loops qw( NestedLoops );
my $iter = NestedLoops([ \#app, \#att1, \#att2 ]);
while ( my ($app, $att1, $att2) = $iter->() ) {
say "$app $att1 $att2";
}
Output:
1 4 7
1 4 8
1 4 9
1 5 7
1 5 8
1 5 9
1 6 7
1 6 8
1 6 9
2 4 7
...
3 6 9
I solved my last issue with formatting, by cheating. I just edited the source files and removed all the \r and \n.
Final code:
use Algorithm::Loops qw( NestedLoops );
use warnings;
open (FILE, app_txt);
($app = (<FILE>));
close (FILE);
my #app = split /,/, $app;
open (FILE, att1_txt);
($att1 = (<FILE>));
close (FILE);
my #att1 = split /,/, $att1;
open (FILE, att2_txt);
($att2 = (<FILE>));
close (FILE);
my #att2= split /,/, $att2;
my $iter = NestedLoops([ \#app, \#att1, \#att2 ]);
while ( my ($app, $att1, $att2) = $iter->() ) {
open (my $fh, '>', 'test');
print $fh "$app $att1 $att2\n";
close $fh;
}
print "done\n";

bash + what the opposite operation of the unset command + add arr member

Deleting value from array in bash is very simple as the following:
remove the first value from array:
arr=(1 2 3 4 5 6)
unset arr[0]
echo ${arr[*]}
2 3 4 5 6
remove the second value from the last array:
unset arr[1]
echo ${arr[*]}
3 4 5 6
But how to add new value to array in bash ? , is it possible?
for example - add the value 10 after the first arr member
3 10 4 5 6
You can do:
arr=(1 2 3 4 5 6)
unset arr[0]
unset arr[1]
arr[1]="${arr[2]}"
arr[2]=10
echo "${arr[#]}"
3 10 4 5 6
To add an item 5 to table arr
arr=(${arr[*]} 5)
Ordering in bash is made throught sort command... Otherwise I advise you to use an other language.

How do I split a text file into blocks using Perl?

I have a data file with lines like this:
A1 2 3 4 5
B 1 2 4
B 7 8 9
A6 7 8 9
B 1 2 3
B 5 6 7
A3 6 9 7
B 2 3 3
B 5 6 6
Using Perl, how do I split the file into a set of arrays (or any other data structure) when the parser hits a /^A/ please?
so I end up with
array1:
A1 2 3 4 5
B 1 2 4
B 7 8 9
array2:
A6 7 8 9
B 1 2 3
B 5 6 7
etc.
Many thanks.
I had to rewrite the answer (after rewritten question)
#arrays = ();
while (<>) {
push(#arrays, []) if /^A/;
push(#{$arrays[-1]}, $_)
}
It is at times like this when I wish $/ could be more than just a string. Nevertheless, there are workarounds.
One could slurp the file in and process with a lookahead assertion. The example below simply prints each string delimited with << >>, but the basic idea is the same regardless of what you want to do with the data:
$ perl -0777 -wE 'say "<<$_>>" for split /(?=^A)/m, <>' file.txt
<<A1 2 3 4 5
B 1 2 4
B 7 8 9
>>
<<A6 7 8 9
B 1 2 3
B 5 6 7
>>
<<A3 6 9 7
B 2 3 3
B 5 6 6
>>

Resources