How to use offset in arrays in bash? - arrays

Here is my code.
#! /bin/bash
array=(3 2 1 0 0 0 0 0 0 0)
for i in {0..10}
do
this=${array:$i:$((i+1))}
echo $this
done
I want to print each number of my number separately. I have used this line to get the array elements using an offset number.
this=${array:$i:$((i+1))}
However I am only getting 3 printed and rest all are new lines. I basically want to print 3, 2, 1 etc on separate lines. How do I correct this?

First, you need to use the whole array array[#], not array.
echo "${array[#]:3:2}"
Then, you may change the index to simple variable names:
this=${array[#]:i:i+1}
And then, you probably need to extract just one value of the list:
this=${array[#]:i:1}
Try this code:
array=(3 2 1 0 0 0 0 0 0 0)
for i in {0..10}
do
this=${array[#]:i:1}
echo "$this"
done

There is no reason to use an array slice here, just access the individual elements of the array. Try this:
#! /bin/bash
array=(3 2 1 0 0 0 0 0 0 0)
for i in {0..10}
do
this=${array[$((i+1))]}
echo $this
done
In general you can access a single element of an array like that: ${array[3]}.
Note that in this case, it would have been preferable to do this:
array=(3 2 1 0 0 0 0 0 0 0)
for this in "${array[#]}"
do
echo $this
done

Related

Any efficient way to identify a set of 1s in a big array?

I have an array called link_slots of 800 elements made of 1, 0 and -1.
E.g. [1 1 1 -1 0 0 0 0 1 1 -1 0 0 1 1 1 1 -1 0 0 ...]. So, 1 denotes occupied, 0 for unoccupied and -1 just to mark the end of a set of 1s.
I want to know the start and end indices of each set of 1s. E.g.,here, start as [1,9,14] and end as [3,10,17]. My code works but found out through Profiler that it takes a lot of time. Is there any efficient way to solve this? Considering that I have to do this thing for multiple arrays for size 800 elements.
i=1;
while(i<numel(link_slots(1,:)) ) %to cycle through whole array
j=i
if(link_slots(1,i)==1) %i.e. if occupied
startt(i)=i %store it in the start array
j=i
while(link_slots(index,j+1)~=-1)
j=j+1
end
endd(i)=j %store the end index upon encountering -1
end
i=j+1
end
data= [1 1 1 -1 0 0 0 0 1 1 -1 0 0 1 1 1 1 -1 0 0]';
the end indices are very easy to find :
I=find(data==-1);
end_indices=I-1;
to find the start indices you want the indices of '1' s which previous value is zero or '-1'
so for example:
temp=[0;data]; % i added a zero to the start of data to use diff function
I=find(diff(temp)>0 & data==1) % here diff function calculates difference between subsequent values of array. so in case of your question if we had ..0 1..diff is 1 and ...

converting tuples into strings

So my problem is i have a tuple with tuples inside it and i want to replace the 1 inside the tuples into # and 0 to .
Although im still to figure that one my myself when i convert the main tuple to a string i dont want the parentises and i want it displayed in columns but its not working so if someone could help me i would appreciate it a lot.
maze = ((1,1,1,1),(1,0,0,1),(1,0,0,1),(1,0,0,1),(1,1,1,1))
def tuplestr(maze):
string = ""
string += str(maze)
return string
so basically in the the result is ((1,1,1,1),(1,0,0,1),(1,0,0,1),(1,0,0,1),(1,1,1,1)) but in a string and i want this as a result
1 1 1 1
1 0 0 1
1 0 0 1
1 0 0 1
1 1 1 1
instead of this ((1,1,1,1),(1,0,0,1),(1,0,0,1),(1,0,0,1),(1,1,1,1)) string

substituting some elements of a matrix with new values bash

I am trying to read in a file, change some parts of it and write it to a new file in bash. I know that I can substitute the parts with the "sed" command but I do not know how to it in my case which is a matrix in the beginning of my file. Here is how my file looks like
alpha
1 0 0
0 1 0
0 0 1
some text here
more numbers here
and I am trying to substitute the values of the matrix above in a for loop like
for i in 1 2 3 4
do
replace 1 0 0
0 1 0
0 0 1
by 1*(1+${i}) ${i}/2 0
${i}/2 1 0
0 0 1
and print the whole file with the substitution to newfile.${i}
done
I want to do this in bash. Any idea how to do this? And I only want to change this part and only this part!
Awk is more suitable for this:
for i in {1..4}; do awk -v i="$i" -f substitute.awk oldfile.txt > newfile.$i; done
using the following substitute.awk script:
{
if( NR == 3 ) { print 1 + i, i / 2, 0 }
else if( NR == 4 ) { print i / 2, 1, 0 }
else print $0
}
(assuming, as you wrote, that the matrix is always in lines 3 through 5; in your example it is in lines 2 through 4)

perl array size is smaller than it should be

I want to initialize 4^9 (=262144) indices of #clump as 0. So I wrote this:
my $k=9;
my #clump=();
my $n=4**$k;
for(my $i=0;$i<$n;$i++){
push(#clump,0);
print "$i ";
}
But it keeps freezing at 261632! I then tried making $n=5^9 (=1953125) and my code stopped at 1952392. So its definitely not a memory issue. This should be simple enough but I can't figure out what's wrong with my code. Help a newbie?
Suffering from buffering?
When I add a sleep 1000 to the end of your program, stream the output to a file, and read the tail of the file, I also observe the last numbers to be printed are 261632 and 1952392. The remaining output is stuck in the output buffer, waiting for some event (the buffer filling up, the filehandle closing, the program exiting, or an explicit flush call) to flush the output.
The buffering can be changed by one of the following statements early in your program
$|= 1;
STDOUT->autoflush(1);
#!/usr/bin/env perl
use strict;
use warnings;
my $k = 9;
my $n = 4 ** $k;
my #clump = (0) x $n;
print join(' ', #clump), "\n";
printf "%d elements in \#clump\n", scalar #clump;
Or,
#!/usr/bin/env perl
use strict;
use warnings;
my $k = 9;
my $n = 4 ** $k;
my #clump;
$#clump = $n - 1;
$_ = 0 for #clump;
print join(' ', #clump), "\n";
printf "%d elements in \#clump\n", scalar #clump;
Output:
...
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
262144 elements in #clump
Also, note that initialization with 0 is almost never required in Perl. Why do you need this?

MATLAB removing rows which has duplicates in sequence

I'm trying to remove the rows which has duplicates in sequence. I have only 2 possible values which are 0 and 1. I have nXm which n shows possible number of bits and m is not important for my question. My goal is to find an matrix which is nX(m-a). The rows a which has the property which includes duplicates in sequence. For example:
My matrix is :
A=[0 1 0 1 0 1;
0 0 0 1 1 1;
0 0 1 0 0 1;
0 1 0 0 1 0;
1 0 0 0 1 0]
I want to remove the rows has t duplicates in sequence for 0. In this question let's assume t is 3. So I want the matrix which:
B=[0 1 0 1 0 1;
0 0 1 0 0 1;
0 1 0 0 1 0]
2nd and 5th rows are removed.
I probably need to use diff.
So you want to remove rows of A that contain at least t zeros in sequence.
How about a single line?
B = A(~any(conv2(1,ones(1,t),2*A-1,'valid')==-t, 2),:);
How this works:
Transform A to bipolar form (2*A-1)
Convolve each row with a sequence of t ones (conv2(...))
Keep only rows for which the convolution does not contain -t (~any(...)). The presence of -t indicates a sequence of t zeros in the corresponding row of A.
To remove rows that contain at least t ones, just change -t to t:
B = A(~any(conv2(1,ones(1,t),2*A-1,'valid')==t, 2),:);
Here is a generalized approach which removes any rows which has given number of consecutive duplicates (not just zero. could be any number).
t = 3;
row_mask = ~any(all(~diff(reshape(im2col(A,[1 t],'sliding'),t,size(A,1),[]))),3);
out = A(row_mask,:)
Sample Run:
>> A
A =
0 1 0 1 0 1
0 0 1 5 5 5 %// consecutive 3 5's
0 0 1 0 0 1
0 1 0 0 1 0
1 1 1 0 0 1 %// consecutive 3 1's
>> out
out =
0 1 0 1 0 1
0 0 1 0 0 1
0 1 0 0 1 0
How about an approach using strings? This is certainly not as fast as Luis Mendo's method where you work directly with the numerical array, but it's thinking a bit outside of the box. The basis of this approach is that I consider each row of A to be a unique string, and I can search each string for occurrences of a string of 0s by regular expressions.
A=[0 1 0 1 0 1;
0 0 0 1 1 1;
0 0 1 0 0 1;
0 1 0 0 1 0;
1 0 0 0 1 0];
t = 3;
B = sprintfc('%s', char('0' + A));
ind = cellfun('isempty', regexp(B, repmat('0', [1 t])));
B(~ind) = [];
B = double(char(B) - '0');
We get:
B =
0 1 0 1 0 1
0 0 1 0 0 1
0 1 0 0 1 0
Explanation
Line 1: Convert each line of the matrix A into a string consisting of 0s and 1s. Each line becomes a cell in a cell array. This uses the undocumented function sprintfc to facilitate this cell array conversion.
Line 2: I use regular expressions to find any occurrences of a string of 0s that is t long. I first use repmat to create a search string that is full of 0s and is t long. After, I determine if each line in this cell array contains this sequence of characters (i.e. 000....). The function regexp helps us perform regular expressions and returns the locations of any matches for each cell in the cell array. Alternatively, you can use the function strfind for more recent versions of MATLAB to speed up the computation, but I chose regexp so that the solution is compatible with most MATLAB distributions out there.
Continuing on, the output of regexp/strfind is a cell array of elements where each cell reports the locations of where we found the particular string. If we have a match, there should be at least one location that is reported at the output, so I check to see if any matches are empty, meaning that these are the rows we don't want to remove. I want to turn this into a logical array for the purposes of removing rows from A, and so this is wrapped with a cellfun call to determine the cells that are empty. Therefore, this line returns a logical array where a 0 means that remove this row and a 1 means that we don't.
Line 3: I take the logical array from Line 2 and invert it because that's what we really want. We use this inverted array to index into the cell array and remove those strings.
Line 4: The output is still a cell array, so I convert it back into a character array, and finally back into a numerical array.

Resources