How to access even elements of array in bash - arrays

I want to echo the even elements of an array in bash, how could this be achieved?

Assuming your array is not sparse (contains no gaps),
Assuming by even you start counting from 1 (and not 0 like bash does), you can do that with a loop on the indexes:
array=(a b c d e f g h)
for index in "${!array[#]}"; do
(( index % 2 )) && echo "${array[index]}"
done
:
outputs:
b
d
f
h

Assuming you're talking about an indexed rather than associative array and you want the values for the even numbered indices rather than the even number values - loop from zero to array size incrementing the index by 2 on each iteration.
Borrowing #Camunsensei's example:
array=(a b c d e f g h)
for (( index=0; index<${#array[#]}; index+=2 )); do
printf 'array[%d]=%q\n' "$index" "${array[index]}"
done
array[0]=a
array[2]=c
array[4]=e
array[6]=g
If that's not what you need then editing your question to include some sample input, expected output, and what you've tried so far would help a lot.

Related

Using a loop's positional parameters inside an inner loop in Raku

Here is the code:
my #s=<a b c d>;
for #s.kv {
for ($^k ... #s.elems) {
printf("%s ", $^v);
}
printf("\n");
}
Expected output is:
# a b c d
# b c d
# c d
# d
But it gives this error (possibly among others)
key 0, val 1 Too few positionals passed; expected 2 arguments but got 1
It looks like the positional variables of the main loop $^k and $^v can't be used inside the inner loop. How to fix it? Thanks.
Update: Typo inside inner loop fixed
So for what you want to do I'd approach it like this :
my #s = <a b c d>;
for ^#s.elems -> $start-index {
for #s[$start-index..*] -> $value {
printf("%s ", $value );
}
print("\n");
}
Though really I'd do this.
my #s = <a b c d>;
(^#s.elems).map( { #s[$_..*].join(" ").say } )
Get the range from 0 to the number of elements in the array. Then the slice from there to the end for each, join on spaces and say.
A note on variables like $^k these are scoped to the current block only (hence why your above code is not working). Generally you only really want to use them in map, grep or other such things. Where possible I'd always advise naming your variables, this makes them scoped inside inner blocks as well.
Scimon Proctor's answer is essentially correct, but I'll try to explain why your example does not work. For starters, kv returns "an interleaved sequence of indexes and values", so this:
my #s=<a b c d>;
.say for #s.kv;
prints
0
a
1
b
2
c
3
d
Essentially, you're doing one turn of the loop for every key and value. Grouping them in pairs using rotor might be closer to what you're looking for:
.say for #s.kv.rotor(2)
which will return:
(0 a)
(1 b)
(2 c)
(3 d)
Since with this we got the value couple with the index, we can do...
my #s=<a b c d>;
for #s.kv.rotor(2) -> ($k, $) {
"{#s[$_]} ".print for ($k..^#s.elems);
printf("\n");
}
Please note that there was also an error in the inner loop, whose range went beyond the actual indices in #s. But, again, Scimon's answer that uses maps is much shorter, idiomatic and straightforward. This one is just kind of dwimming your original program. As a matter of fact, we are throwing away the values, so this would actually be:
my #s=<a b c d>;
for #s.keys -> $k {
"{#s[$_]} ".print for ($k..^#s.elems);
printf("\n");
}
No need to use kv at all, and just make do with the keys.

Filling a row and columns of a ndarray with a loop

I'm starting with Python and I have a basic question with "for" loop
I have two array which contains a values of a same variables:
A = data_lac[:,0]
In the first array, I have values of area and in the second on, values of mean depth.
I would like to find a way to automatize my calculation with different value of a parameter. The equation is the following one:
g= (np.sqrt(A/pi))/n
Here I can calculte my "g" for each row. Now I want to have a loop with differents values of "n". I did this:
i=0
while i <= len(A)-1:
for n in range(2,6):
g[i] = (np.sqrt(A[i]/pi))/n
i += 1
break
In this case, I just have one column with the calculation for n = 2 but not the following one. I tried to add a second dimension to my array but I have an error message saying that I have too many indices for array.
In other, I would like this array:
g[len(A),5]
g has 5 columns each one calculating with a different "n"
Any tips would be very helpful,
Thanks
Update of the code:
data_lac=np.zeros((106,7))
data_lac[:,0:2]=np.loadtxt("/home...", delimiter=';', skiprows=1, usecols=(0,1))
data_lac[:,1]=data_lac[:,1]*0.001
#Initialisation
A = data_lac[:,0]
#example for A with 4 elements
A=[2.1, 32.0, 4.6, 25]
g = np.zeros((len(A),))
I believe you share the indexes within both loops. You were increasing the i (index for the upper while loop) inside the inner for loop (which index with n).
I guess you have A (1 dim array) and you want to produce G (2 dim array) with size of (Len(A, 5))
I am not sure I'm fully understand your require output but I believe you want something like:
i=0
while i <= len(A)-1:
for n in range(2,6):
g[i][n-2] = (np.sqrt(A[i]/pi))/n # n-2 is to get first index as 0 and last as 4
i += 1 # notice the increace of the i is for the upper while loop
break
Important - remember that in python indentation means a lot -> so make sure the i +=1 is under the while scope and not indent to be inside the for loop
Notice - G definition should be as:
g = np.zeros((len(A),4), dtype=float)
The way you define it (without the 4) cause it to be 1 dim array and not 2-dim

remove redundancy in a file based on two fields, using awk

I'm trying to remove duplicate lines in a very large file (~100,000 records) according to the values of the first two columns without taking into account their order, and then print those fields + the other columns.
So, from this input:
A B XX XX
A C XX XX
B A XX XX
B D XX XX
B E XX XX
C A XX XX
I'd like to have:
A B XX XX
A C XX XX
B D XX XX
B E XX XX
(That is, I want to remove 'B A' and 'C A' because they already appear in the opposite order; I don't care about what's in the next columns but I want to print it too)
I've the impression that this should be easy to do with awk + arrays, but I can't come with a solution.
So far, I'm tinkering with this:
awk '
NR == FNR {
h[$1] = $2
next
}
$1 in h {
print h[$1],$2}' input.txt
I'm storing the second column in an array indexed by the first (h), and then check if there are occurrences of the first field in the stored array. Then, print the line. But something's wrong and I have no output.
I'm sorry because my code is not helpful at all but I'm kind of stuck with this.
Do you have any ideas?
Thanks a lot!
Just keep track of the things that appear on the two formats:
$ awk '!seen[$1,$2]++ && !seen[$2,$1]++' file
A B XX XX
A C XX XX
B D XX XX
B E XX XX
Which is equivalent to awk '!(seen[$1,$2]++ || seen[$2,$1]++)' file.
Note it is also equivalent to not having ++ the second expression (see comments):
awk '!seen[$1,$2]++ && !seen[$2,$1]' file
Explanation
The typical approach to print unique lines is:
awk '!seen[$0]++' file
This creates an array seen[] whose indexes are the lines that have appeared so far. So if it is new, seen[$0] is 0 and gets incremented to 1. But previously it is printed because the expression ! var ++ evaluates ! var first (and in awk, True triggers the action of printing the current line). When the line has been seen already, seen[$0] has a positive value, so !seen[$0] is false and doesn't trigger the printing action.
In your case you want to keep track of what appeared, no matter the order, so what I am doing is to store the indexes in both possible positions.
use as below
$awk '{if( $1$2 in a == 0 && $2$1 in a == 0 ) a[$1$2]=$0; } END{ for(i in a)print a[i]; }' input.txt
Explanation:
command is storing the record in array (a) with array key as combination of first and second field (i.e $1$2 and $2$1) is not already present in array. Once complete file is read then print the array (a).
# ($1$2 in a) => checks if there is any key with $1$2 in array a
# if it's not present then it return 0
# and if both combination $1$2 and $2$1 are not present then store the record in array a
if( $1$2 in a == 0 && $2$1 in a == 0 ) a[$1$2]=$0;
# below print the array a (which stores complete unique record) at the end
END{ for(i in a) print a[i]; }'

Stop Matlab from treating a 1xn matrix as a column vector

I'm very frustrated with MATLAB right now. Let me illustrate the problem. I'm going to use informal notation here.
I have a column cell vector of strings called B. For now, let's say B = {'A';'B';'C';'D'}.
I want to have a matrix G, which is m-by-n, and I want to replace the numbers in G with the respective elements of B... For example, let's say G is [4 3; 2 1]
Let's say I have a variable n which says how many rows of G I want to take out.
When I do B(G(1:2,:)), I get what I want ['D' 'C'; 'B' 'A']
However, if I do B(G(1:1,:)) I get ['D';'C'] when what I really want to get is ['D' 'C']
I am using 1:n, and I want it to have the same behavior for n = 1 as it does for n = 2 and n = 3. Basically, G actually is a n-by-1500 matrix, and I want to take the top n rows and use it as indexes into B.
I could use an if statement that transposes the result if n = 1 but that seems so unnecessary. Is there really no way to make it so that it stops treating my 1-by-n matrix as if it was a column vector?
According to this post by Loren Shure:
Indexing with one array C = A(B) produces output the size of B unless both A and B are vectors.
When both A and B are vectors, the number of elements in C is the number of elements in B and with orientation of A.
You are in second case, hence the behaviour you see.
To make it work, you need to maintain the output to have as many columns as in G. To achieve the same, you can do something like this -
out = reshape(B(G(1:n,:)),[],size(G,2))
Thus, with n = 1:
out =
'D' 'C'
With n = 2:
out =
'D' 'C'
'B' 'A'
I think this will only happen in 1-d case. In default, matlab will return column vector since it is the way how it stores matrix. If you want a row vector, you could just use transpose. Well in my opinion it should be fine when n > 1.

Is it always possible to order a multi-dimensional array in all dimensions? How?

Suppose, I have an n-dimensional array of integers (for n=1 it's a vector, for n=2 it's a rectangular matrix, for n=3 it's a parallelepiped, etc). I need to reorder elements of the array so that elements in each row, column, etc are in a non-decreasing order.
Is it possible for any input array?
Is the required ordering unique for any input array? I just realized that the answer for this question in general is no, e.g. for square matrices.
Is the required ordering unique for any input array that has different lengths in all dimensions?
What is the fastest algorithm to produce the required ordering?
Is it possible for any input array?
Yes, if we will look on the array as a single dimension array, with the same number of elements, and then sort it, by traversing it back to the original n-dimensions array, it remains sorted, since for each i1,....,i_k,...,i_m: for all i_k < i_k':
i_1 + n1*i_2 + n2^2*i_3 + .... (n_k-1)^(k-1)(i_k) + ... < i_1 + n1*i_2 + n2^2*i_3 + .... (n_k-1)^(k-1)(i_k') + ...
Thus (the array is ordered):
arr[i_1 + n1*i_2 + n2^2*i_3 + .... (n_k-1)^(k-1)(i_k) + ...] < arr[ i_1 + n1*i_2 + n2^2*i_3 + .... (n_k-1)^(k-1)(i_k') + ...]
Thus (back to original array):
arr[i_1][i_2]...[i_k]... < arr[i_1][i_2]...[i_k']...
As for the 2nd question:
Is the required ordering unique for any input array that has different
lengths in all dimensions?
No:
1 1 1 3
3 4 1 4
5 6 5 6
What is the fastest algorithm to produce the required ordering?
One solution is suggested already: regard it is a big long array and sort it.
Complexity is O(n_1*n_2*...*n_m*log(n_1*n_2*...*n_m))
My gut says if you could do it faster, you could sory faster then O(nlogn), but I have no proof for this claim, so it might be wrong.
Let me elaborate more about Alptigin Jalayr's idea.
Suppose we have rows sorted, so for the following data, we have a <= b and c <= d.
. .
..., a, ..., b, ...
. .
..., c, ..., d, ...
. .
When a is greater than c, i.e. c <a, then swap of them gives us c < b since a <= b, and a <=d since b <= d (if b > d, we swap b and d as well). In a word, sorting rows first and then columns next can give you the desired matrix.

Resources