How to translate file int 2-D array? - arrays

I have a file array.txt that consists of numbers. I need to make a 2D array from it. How can I do that?
0 6 10 0 0 0 0 0 0 0
6 0 12 11 14 0 0 0 0 0
10 12 0 12 0 0 8 16 0 0
0 11 12 0 0 6 3 0 0 0
0 14 0 0 0 4 0 0 6 0
0 0 0 6 4 0 0 0 12 0
0 0 8 3 0 0 0 0 16 6
0 0 16 0 0 0 0 0 0 8
0 0 0 0 6 12 16 0 0 13
0 0 0 0 0 0 6 8 13 0

You must have 2 variable for row and column ...Read the file until read new line, Put every number in arr[column][row] and add 1 to column, When read new line add 1 to row and read number in new line again.

+combo_ci is correct. You need to read the file, look for the spaces to increment the column and the new line combo CR-LF to increase the row. Here is a modified example that I worked up to read an Excel CSV file. The only difference is that I replaced the comma separator with a space
'Reading a space deliminted file
TextWindow.Show()
LoadFile()
TextWindow.WriteLine("File Size = " + Text.GetLength(DataIn))
ParseFile()
TextWindow.WriteLine("Rows = " + rows + ", Columns = " + cols)
DisplayTable()
'---------------------------------------------------------------
'Read the contents of the CSV style (spaces instead of commas) file into memory
Sub LoadFile
filename = Program.Directory
filename = filename + "\excelintoSB.csv"
DataIn = File.ReadContents(filename)
EndSub
'Parse the file contents, looking for spaces and line breaks to separate the cells.
Sub ParseFile
row = 1
col = 1
cell = ""
For i =1 To Text.GetLength(DataIn) 'Look at each character in the file
ch = Text.GetSubText(DataIn,i,1)
'Is it a space or a cariage return? Store the Cell
If ch = " " or text.GetCharacterCode(ch) = 13 then
table[row][col] = cell
cell = ""
If text.GetCharacterCode(ch) = 13 Then 'end of row, start a new one
row = row + 1
col = 1
Else 'New Cell, current row
col = col + 1
If col > maxCol then 'Keep track of how many columns we have encountered
maxCol = col
endif
endif
ElseIf text.GetCharacterCode(ch) <> 10 then 'build the cell, ignoring line feeds.
cell = cell + ch
EndIf
EndFor
rows = row - 1
cols = maxCol
EndSub
'Display the table in row / column format
Sub DisplayTable
TextWindow.WriteLine("The Table --- ")
For i = 1 To rows
TextWindow.Write("[ ")
For j = 1 To cols
TextWindow.Write(table[i][j] + " ")
EndFor
TextWindow.WriteLine("]")
EndFor
EndSub

Related

How to balance unique values in an array Matlab

I have a vector
Y = [1 1 0 0 0 1 1 0 1 0 1 1 1 0 0 0 1 1 0 0 0 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 0 0]
1 occurs 17 times
0 occurs 21 times
How can I randomly remove 0s so that both values have equal amounts, such as 1 (17 times) and 0 (17 times)?
This should also work on much bigger matrix.
Starting with your example
Y = [1 1 0 0 0 1 1 0 1 0 1 1 1 0 0 0 1 1 0 0 0 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 0 0]
You can do the following:
% Get the indices of the value which is more common (`0` here)
zeroIdx = find(~Y); % equivalent to find(Y==0)
% Get random indices to remove
remIdx = randperm(nnz(~Y), nnz(~Y) - nnz(Y));
% Remove elements
Y(zeroIdx(remIdx)) = [];
You could combine the last two lines, but I think it would be less clear.
The randperm line is choosing the correct number of elements to remove from random indices between 1 and the number of zeros.
If the data can only have two values
Values are assumed to be 0 and 1. The most common value is randomly removed to equalize their counts:
Y = [1 1 0 0 0 1 1 0 1 0 1 1 1 0 0 0 1 1 0 0 0 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 0 0]; % data
ind0 = find(Y==0); % indices of zeros
ind1 = find(Y==1); % indices of ones
t(1,1:numel(ind0)) = ind0(randperm(numel(ind0))); % random permutation of indices of zeros
t(2,1:numel(ind1)) = ind1(randperm(numel(ind1))); % same for ones. Pads shorter row with 0
t = t(:, all(t,1)); % keep only columns that don't have padding
result = Y(sort(t(:))); % linearize, sort and use those indices into the data
Generalization for more than two values
Values are arbitrary. All values except the least common one are randomly removed to equalize their counts:
Y = [0 1 2 0 2 1 1 2 0 2 1 2 2 0 0]; % data
vals = [0 1 2]; % or use vals = unique(Y), but absent values will not be detected
t = [];
for k = 1:numel(vals) % loop over values
ind_k = find(Y==vals(k));
t(k, 1:numel(ind_k)) = ind_k(randperm(numel(ind_k)));
end
t = t(:, all(t,1));
result = Y(sort(t(:)));

Find regions of contiguous zeros in a binary array

I have
x=[ 1 1 1 1 0 0 1 1 1 0 1 0 0 0 0 0 0 1 0 1]
I want to find all the regions that have more than 5 zeros in a row. I want to find the index where it starts and where it stops.
In this case I want this: c=[12 18]. I can do it using for loops but I wonder if there is any better way, at least to find if there are some regions where this 'mask' ( mask=[0 0 0 0 0] ) appears.
A convolution based approach:
n = 5;
x = [0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 1 1 0 1 0];
end_idx = find(diff(conv(~x, ones(1,n))==n)==-1)
start_idx = find(diff(conv(~x, ones(1,n))==n)==1) - n + 2
returning
end_idx =
6 14 25
start_idx =
1 9 20
Note that this part is common to both lines: diff(conv(~x, ones(1,n))==n) so it would be more efficient to pull it out:
kernel = ones(1,n);
convolved = diff(conv(~x, kernel)==n);
end_idx = find(convolved==-1)
start_idx = find(convolved==1) - n + 2
You can use regexp this way:
convert the array into a string
remove the blanks
use regexp to find the sequence of 0
A possible implementation could be:
x=[ 1 1 1 1 0 0 1 1 1 0 1 0 0 0 0 0 0 1 0 1]
% Convert the array to string and remove the blanks
str=strrep(num2str(x),' ','')
% Find the occurrences
[start_idx,end_idx]=regexp(str,'0{6,}')
This gives:
start_idx = 12
end_idx = 17
where x(start_idx) is the first element of the sequence and x(end_idx) is the last one
Applied to a more long sequence, start_idx and end_idx results being arrays:
x=[0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 1 1 0 1 0]
start_idx =
1 9 20
end_idx =
6 14 25

VBA function to iterate through cells, replacing a cell with the relative column header value

I'm trying to convert a data matrix to a new standard that should fit a specific analysis software.
The initial matrix looks like this:
real char num 10 10 25 26 26 56
--------------------------------
state num 1 2 9 4 6 3
--------------------------------
name 1 0 0 1 1 0 1
name 2 1 0 0 0 0 0
name 3 0 1 1 0 0 1
name 4 0 1 0 0 1 0
name 5 1 0 0 0 0 0
name 6 0 0 1 0 1 0
I've been trying to achieve this:
real char num 10 10 25 26 26 56
--------------------------------
state num 1 2 9 4 6 3
--------------------------------
name 1 0 0 9 4 0 3
name 2 1 0 0 0 0 0
name 3 0 2 9 0 0 3
name 4 0 2 0 0 6 0
name 5 1 0 0 0 0 0
name 6 0 0 9 0 6 0
Essentially, what I'm trying to do is:
1. For every column, look in every cell for a number other than 0;
2. If this condition is achieved, replace the cell value with the relative "state" header. Meaning, for instance, if A4 <> 0, then replace it with A3 value.
The code I've used is as follows:
Sub Iterate_replace()
Sheets("matrix").Select
Dim r As Range, cell As Range, state As Range
Set r = Range("C3")
Set state = Range("C2")
For Each cell In r
If cell.Value <> "0" Then
cell.Value = state.Value
End If
Next
End Sub
It works fine in a defined range of one single column, but I'm having trouble making it dynamic. Should I use R1C1 notation to refer to the cells in the range? Everything related that I could find never explicits how to make this iteration more flexible. Should I use nested loops? Loops are a very difficult thing for me to grasp, still, so, please be patient.
I'd appreciate if anyone could point me to the right direction. Thanks!
I am assuming that there is nothing else on each sheet than the matrix in question. In that case you should be able to make you procedure dynamic by modifying your code like the following:
Sub Iterate_replace()
Sheets("matrix").Select
Dim i As Integer, j As Integer
Dim state As Range
Set state = Range("C2")
'Loops through each row and each column in matrix
For i = state.Column To ActiveSheet.Cells(state.Row, Columns.Count).End(xlToLeft).Column
For j = state.Row + 1 To ActiveSheet.Cells(Rows.Count, state.Column).End(xlUp).Row
If Cells(j, i).Value <> 0 Then
Cells(j, i).Value = Cells(state.Row, i).Value
End If
Next j
Next i
End Sub
This will loop through each column and each row in your matrix if you have defined in what cell the most left state value is located.

array not being read properly

I have a 2D array. I am iterating all the 8 rows and 10 columns and reading the values using a for loop. Here is the our array and the 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 2 1 1 1 0 0 0 0 0
0 0 0 1 2 1 2 2 1 2 1 2 1 0 0 0
0 0 0 1 2 1 2 2 1 2 1 2 1 0 0 0
0 0 0 1 2 1 2 2 1 2 1 2 1 0 0 0
0 0 0 1 2 1 2 2 1 2 1 2 1 0 0 0
0 0 0 1 2 1 2 2 1 2 1 2 1 0 0 0
0 0 0 1 2 1 2 2 1 2 1 2 1 0 0 0
0 0 0 1 2 1 2 2 1 2 1 2 1 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 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
empty row board[3][3] = 0 empty row board[3][4] = 1
empty row board[4][3] = 0 empty row board[4][4] = 2
empty row board[5][3] = 0 empty row board[5][4] = 1
empty row board[6][3] = 0 empty row board[6][4] = 2
empty row board[7][3] = 0 empty row board[7][4] = 2
empty row board[8][3] = 0 empty row board[8][4] = 1
empty row board[9][3] = 0 empty row board[9][4] = 2
empty row board[10][3] = 0 empty row board[10][4] = 1
empty row board[11][3] = 0 empty row board[11][4] = 2
empty row board[12][3] = 0 empty row board[12][4] = 1
The actual array is surrounded by buffer of zeros (atleast 3 on each side). When we try to read row =3, it doesn't read the elements but rather reads them as all zeros. We have printed below the array the elements of row 3 and elements of row+1, which is 4. It can read all elements from row 4 but nothing from row 3. WHY? Please Help!!!
#Mat
Posted Code:
We are trying to find if the row is empty or not.
int emptyRow(int row){
int i, counter;
counter = 0;
for(i=3; i<=num_col+2; i++) {
printf ("empty row board[%d][%d] = %d ", i, row, board[i][row]);
printf ("empty row board[%d][%d] = %d\n", i, row+1, board[i][row+1]);
if(board[i][row] == 1 || board[i][row] == 2 || board[i][row] == 3)
counter++;
}
return counter; /* Counter = 0 means its empty*/
}
The row being passed is 3, the counter counts the number of elements in the row, num_col is the number of columns.
The functions returns counter = 0 which means row 3 is empty.
We are reading the input from a file and printing it. This code is part of an AI we are working on, so cannot post all of the code since it is complicated. Print board is posted below:
Row 3 is our boundary condition, so we dont care whats above row 3 but we need to read in row 3 properly
void print_board(){
int i;
int j;
for(i=0;i< 16; i++){
for(j=0;j<16;j++){
printf("%d ", board[j][i]);
}
printf("\n");
}
}
Assuming the displayed output is from a call to print_board(), and the debugging output shown is from a call to emptyRow(3), then the only explanation that makes sense is that board was modified between those two calls. Check your software to make sure that the board contains the values you expect it to at each stage leading up to the call to emptyRow(3).
Use these lines,
printf ("empty row board[%d][%d] = %d ", i, row, board[row][i]);
printf ("empty row board[%d][%d] = %d\n", i, row+1, board[row+1][i]);
if(board[row][i] == 1 || board[row][i] == 2 || board[row][i] == 3)
This should work as expected. See previous answers re row/col mix up.
This assumes the board array is in fact 16 x 16 in size, and num_col+2 evaluates to 12.
I would use gdb to run the program and then you can use print board[3], print board[4], etc to see what the program sees.
Row and column interchanged up in the code of printing the first set of whole array as matrix
Use
void print_board(){
int i;
int j;
for(i=0;i< 16; i++){
for(j=0;j<16;j++){
printf("%d ", board[i][j]);
}
printf("\n");
}
}

A question about matrix manipulation

Given a 1*N matrix or an array, how do I find the first 4 elements which have the same value and then store the index for those elements?
PS:
I'm just curious. What if we want to find the first 4 elements whose value differences are within a certain range, say below 2? For example, M=[10,15,14.5,9,15.1,8.5,15.5,9.5], the elements I'm looking for will be 15,14.5,15.1,15.5 and the indices will be 2,3,5,7.
If you want the first value present 4 times in the array 'tab' in Matlab, you can use
num_min = 4
val=NaN;
for i = tab
if sum(tab==i) >= num_min
val = i;
break
end
end
ind = find(tab==val, num_min);
By instance with
tab = [2 4 4 5 4 6 4 5 5 4 6 9 5 5]
you get
val =
4
ind =
2 3 5 7
Here is my MATLAB solution:
array = randi(5, [1 10]); %# random array of integers
n = unique(array)'; %'# unique elements
[r,~] = find(cumsum(bsxfun(#eq,array,n),2) == 4, 1, 'first');
if isempty(r)
val = []; ind = []; %# no answer
else
val = n(r); %# the value found
ind = find(array == val, 4); %# indices of elements corresponding to val
end
Example:
array =
1 5 3 3 1 5 4 2 3 3
val =
3
ind =
3 4 9 10
Explanation:
First of all, we extract the list of unique elements. In the example used above, we have:
n =
1
2
3
4
5
Then using the BSXFUN function, we compare each unique value against the entire vector array we have. This is equivalent to the following:
result = zeros(length(n),length(array));
for i=1:length(n)
result(i,:) = (array == n(i)); %# row-by-row
end
Continuing with the same example we get:
result =
1 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0
0 0 1 1 0 0 0 0 1 1
0 0 0 0 0 0 1 0 0 0
0 1 0 0 0 1 0 0 0 0
Next we call CUMSUM on the result matrix to compute the cumulative sum along the rows. Each row will give us how many times the element in question appeared so far:
>> cumsum(result,2)
ans =
1 1 1 1 2 2 2 2 2 2
0 0 0 0 0 0 0 1 1 1
0 0 1 2 2 2 2 2 3 4
0 0 0 0 0 0 1 1 1 1
0 1 1 1 1 2 2 2 2 2
Then we compare that against four cumsum(result,2)==4 (since we want the location where an element appeared for the forth time):
>> cumsum(result,2)==4
ans =
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 1
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
Finally we call FIND to look for the first appearing 1 according to a column-wise order: if we traverse the matrix from the previous step column-by-column, then the row of the first appearing 1 indicates the index of the element we are looking for. In this case, it was the third row (r=3), thus the third element in the unique vector is the answer val = n(r). Note that if we had multiple elements repeated 4 times or more in the original array, then the one first appearing for the forth time will show up first as a 1 going column-by-column in the above expression.
Finding the indices of the corresponding answer value is a simple call to FIND...
Here is C++ code
std::map<int,std::vector<int> > dict;
std::vector<int> ans(4);//here we will store indexes
bool noanswer=true;
//my_vector is a vector, which we must analize
for(int i=0;i<my_vector.size();++i)
{
std::vector<int> &temp = dict[my_vector[i]];
temp.push_back(i);
if(temp.size()==4)//we find ans
{
std::copy(temp.begin(),temp.end(),ans.begin() );
noanswer = false;
break;
}
}
if(noanswer)
std::cout<<"No Answer!"<<std::endl;
Ignore this and use Amro's mighty solution . . .
Here is how I'd do it in Matlab. The matrix can be any size and contain any range of values and this should work. This solution will automatically find a value and then the indicies of the first 4 elements without being fed the search value a priori.
tab = [2 5 4 5 4 6 4 5 5 4 6 9 5 5]
%this is a loop to find the indicies of groups of 4 identical elements
tot = zeros(size(tab));
for nn = 1:numel(tab)
idxs=find(tab == tab(nn), 4, 'first');
if numel(idxs)<4
tot(nn) = Inf;
else
tot(nn) = sum(idxs);
end
end
%find the first 4 identical
bestTot = find(tot == min(tot), 1, 'first' );
%store the indicies you are interested in.
indiciesOfInterst = find(tab == tab(bestTot), 4, 'first')
Since I couldn't easily understand some of the solutions, I made that one:
l = 10; m = 5; array = randi(m, [1 l])
A = zeros(l,m); % m is the maximum value (may) in array
A(sub2ind([l,m],1:l,array)) = 1;
s = sum(A,1);
b = find(s(array) == 4,1);
% now in b is the index of the first element
if (~isempty(b))
find(array == array(b))
else
disp('nothing found');
end
I find this easier to visualize. It fills '1' in all places of a square matrix, where values in array exist - according to their position (row) and value (column). This is than summed up easily and mapped to the original array. Drawback: if array contains very large values, A may get relative large too.
You're PS question is more complicated. I didn't have time to check each case but the idea is here :
M=[10,15,14.5,9,15.1,8.5,15.5,9.5]
val = NaN;
num_min = 4;
delta = 2;
[Ms, iMs] = sort(M);
dMs = diff(Ms);
ind_min=Inf;
n = 0;
for i = 1:length(dMs)
if dMs(i) <= delta
n=n+1;
else
n=0;
end
if n == (num_min-1)
if (iMs(i) < ind_min)
ind_min = iMs(i);
end
end
end
ind = sort(iMs(ind_min + (0:num_min-1)))
val = M(ind)

Resources