Writing a cell array of strings to Excel from Matlab? - excel

I want to write the names of genes into excel but when I run this code matlab doesnt write anything into excel. The cells I want filled are left blank. I cant seem to figure out what I am missing in my code. names is a cell array of string names.
function nameWriter()
x = importdata('mitominerratmitochondrialoutermembraneproteins');
names = {};
n = length(x.textdata);
counter = 0;
for i = 1:n
if strncmp(x.textdata(i),'>', 1) ==1
names{end+1} = x.textdata(i);
counter = counter +1;
end
end
xlswrite('aacount2.xls', names, 'B1:CB1');
end

I believe the likely source of your error is that you are not taking into account that x.textdata is going to be a cell array of strings (as described in the table in the IMPORTDATA documentation for the output argument A). When you assign data to names like so:
names{end+1} = x.textdata(i);
You are actually placing a cell array inside another cell array, and XLSWRITE apparently can't handle nested cell arrays (i.e. it outputs blank fields for cell elements of the input that contain cell arrays). You should instead use curly braces, not parentheses, to access the cell contents of x.textdata, like so:
names{end+1} = x.textdata{i};

Related

using INDIRECT function with dynamic array formula syntax (Excel O365)

I am using the new dynamic array functions introduced in excel in 2018 (e. g. SEQUENCE, UNIQUE etc. functions).
I have a list of cell references that are that are generated dynamically, and would like to apply the INDIRECT function to these list items. A simplified example:
cell A1: =SEQUENCE(5) (results in rows column A values 1,2,3,4,5 as expected)
cell B1: ="A"&A1# (results in rows column B values A1, A2, A3, A4, A5 as expected)
cell C1: =INDIRECT(B1#) this should give me rows in column C values 1,2,3,4,5, but in fact gives me #VALUE ,#VALUE ,#VALUE ,#VALUE ,#VALUE
So the formula properly recognizes the number of rows of the original dynamic array, but for some reason does not dereference the cells properly. The strings seem to be of the proper format - a simple string function such as LEN also works: setting C1 to =LEN(B1#) results in 5 rows of the value 2.
The syntax per se seems to be OK.. for the special case of =SEQUENCE(1) in cell A1 everything works as intended. I tried the R1C1 reference format also, same result
EDIT
Overall I am trying to achieve the following
import a list form a non-Excel data source list is not a dynamic array, it's just a TSV import. I don't now beforehand how many items are in this list, and it can vary a lot
do several different calculations on values of this list.
so far my approach was to use the COUNT function to determine the number of items in the imported list, and then use that to create the second list using SEQUENCE and INDEX to retrieve values.
the problem arises for some calculations where the data contains references to other rows so I have to use indirect addressing to get at that data
The INDIRECT function cannot accept an array for an argument.
In other words:
=INDIRECT({"a1","a2"}) --> #VALUE! | #VALUE!
So you could, for example, refer to each cell in column B as a single cell:
eg:
C1: =INDIRECT(B1)
and fill down.
Depending on how you are using this, you could also use the INDEX function to return an individual element
To return the third element in the array generated by B1#:
=INDIRECT(INDEX(B1#,3))
EDIT:
After reading your comment, and depending on details you have not shared, you may be able to use a variation of the INDEX function.
For example, to return the contents of A1:A5, based on your SEQUENCE function, you can use:
=INDEX($A:$A, SEQUENCE(5))
but exactly how to apply this to your actual situation depends on the details.
As Rosenfeld points out, INDIRECT() does not accept an array as an input. If you need a function that:
"acts" like INDIRECT()
can accept an array as an input
can return an array as an output
Then we can make our own:
Public Function Indirect_a(rng As Range)
Dim arr, i As Long, j As Long
Dim rngc As Long, rngr As Long
rngc = rng.Columns.Count
rngr = rng.Rows.Count
ReDim arr(1 To rngr, 1 To rngc)
For i = 1 To rngc
For j = 1 To rngr
arr(j, i) = Range(rng(j, i).Value)
Next j
Next i
Indirect_a = arr
End Function
and use it like:
Since it creates a "column-compatible" array, it will spill-down dynamically in Excel 365.It can be used in versions of Excel prior to 365, but it must be array-entered into the block it occupies.
You can use the following formula
=BYROW(B1#,LAMBDA(a,INDIRECT(a)))

Retrieve ranges instead of Strings from array formula result in Excel

Having the nest Formula:
"=IF(Hoja1!$A$4=$A$15:$A$22),IF($B$4=$B$15:$B$22),IF($F$15:$F$22=0,$A$15:$A$22)))"
The resulting array is like so:
{FALSE\FALSE\FALSE\FALSE\FALSE\"Title 6"\FALSE\FALSE}
get an array that is set of booleans, and in this case I get String, but what I want to get is Ranges so I can know the position of that gotten non False result in the resulting array.
I know I could do the same using loops in VBA but my goal was to make it using formulas.
I don't know, maybe there is some built-in function that retrieves ranges that I don't know of.
Alternatively, I thought that having a known Range like $A$15:$F$22 I could get the index numbers of the resulting array that has a non false value and make a Range.Cells(index1, index2) using the 2 indexes of the array.
Also, I thought that using the MATCH function could do it.
For example
Match(<>False, {false\"string value"},0)
And so retrieve the row number that I can then use in a .Cell().
But It does not work. Can I do also a excluding match?
What do you suggest? Any easy/fast solution for this?
Reference to get the date:
Data source
I found a solution that was almost in front of my eyes.
I haven't tried using more than one possible search in an array constant (result of an aray formula).
It works for sure in array constant results that has one non empty/non-false results.
Using MATCH() was the solution.
Using the previous conditional formula I got an array with all results FALSE, except for one. Since the non empty/false result is a String and I want to know what is the range that result is in, using the data source range I extract that cell using the row index taken from the MATCH function, and then with simple VBA I have the range I wanted, like so.
Dim F As String
Dim Res As Integer
Dim R As Range
Set R = Range("$A$15:$A$22")
F = "=MATCH($A$4,IF($A$4=$A$15:$A$22),IF($B$4=$B$15:$B$22),IF($F$15:$F$22=0,$A$15:$A$22)))),0)"
'We get the index number of the desired value in the array that
we got in *IF* parts of the array formula.
Res = Hoja1.Evaluate(F)
'Since The position in the array of the element we want is the same as the row number inside the range the value we searched for is in, we can get that range/cell easily.
Set R = R.Cells(Res, 1) 'Or the column I want.
Debug.Print R.Address
The result is $A$18.
As we expected it matches, since inside the $A$15$:$A$22 the value we looked for is in the 4th row inside that source range.
We can get other columns for that match as well.

Sum of an array of numbers, separated by commas in 1 cell, only if there are at least 5 elements

I need the sum of an array of elements in the same cell.
They are separated by commas.
If there are <5 elements then DON'T calculate the sum of that cell.
Example:
cell 1A: 2,1,2,3,1 cell 1B: 9 (the sum)
cell 2A: 1, 2 cell 2B: -- (nothing as there are less than five elements).
I have tried to explain myself. Hope it's clear.
I asked a similar question here:
Old Question
But you have an additional requirement, so try the following User Defined Function:
Public Function SumWithin(s As String) As Variant
If s = "" Then
SumWithin = ""
Exit Function
End If
If InStr(1, s, ",") = 0 Then
SumWithin = ""
Exit Function
End If
arry = Split(s, ",")
If UBound(arry) < 4 Then
SumWithin = ""
Exit Function
End If
For Each a In arry
SumWithin = SumWithin + CDbl(a)
Next a
End Function
Some examples:
This approach avoids all the extra cells required for the typical Text-to-Columns approach.It is possible to do this without VBA, but it involves array formulas.
You can achieve this using the name manager (Ctrl+F3) to trick excel into reading the list as an array, I called my named range "valueArray":
=EVALUATE("{"&SUBSTITUTE(Sheet1!$A2," ","")&"}")
Note that there is no absolute referencing for the row argument and that it starts on the same row as the data (to align the first use of the array correctly).
You could just reference Sheet1!$A2 directly being wrapped in EVALUATE() and the curly brackets but SUBSTITUTE() has been used to make sure the data won't be compromised by spaces.
Now that you have the array, you can perform your logical on it with ease, if an error is thrown or the cell is blank when you expect a result, it is likely that one of the values hasn't parsed as a number (perhaps a letter or two is in there):
=IF(COUNT(valueArray)>4,SUM(valueArray),"")

Using Xlswrite for cell array

I understand that the xlswrite cannot directly populate the contents of the cell array to the excel sheet. Somehow I'm missing a logic in my code where I need to populate every single element exported to a sheet. say my cell array has cells in it and characters example
Names = (1x1 cell) (1x1 cell) (1x1 cell) (1x1 cell)
or say
Names= {{'Brian'};{'Andy'};{'Katherine'};{'crystal'};{'Thomas'};{'Michael'}; {'Maria'}.........};
tried xlswrite directly but it didn't work. Understood the point that it can print one at a time (correct me if im wrong).
saveto = 'D:\Data\';
xlswrite([saveto,'test'],Names{1},'A1');
would work only for one element in cell. Writing a for loop is not helping me as well
for aa=1:length(Names)
saveto = 'D:\Data\';
xlswrite([saveto,'test'],Names{aa},'A1:A2000'); % A2000 is used as a random number
end
your help is appreciated.
Try to "flatten" your Names before writing to the xls:
Names= {{'Brian'};{'Andy'};{'Katherine'};{'crystal'};{'Thomas'};{'Michael'};{'Maria'}}
NamesToWrite = reshape([Names{:}], size(Names));
then use xlswrite on NamesToWrite:
saveto = 'D:\Data\';
xlswrite([saveto,'test.xls'],NamesToWrite);
This happens because, if you pass a cell array to the function, its elements need to be either numeric scalars or strings.

Writing strings into excel using Matlab?

I am writing a cell array of string into Excel from Matlab. I have a cell array data{} that I am trying to write into Matlab. It should writting three large lengths of strings to excel since the strcmp passes 3 times. Currently it is only writing the last set of strings into excel. data = { {1x25} {1x35} {1x20} } looks like this. Also I would like to be able to write the data into three cells instead of getting copyied into as many cells as there are lines in the element of the cell array. Is this possible to do with Matlab to excel?
done = {}
for i = 1:3
q = strcmp(x_gene_ID{i},locus_tags{i});
if q ==1
done{end+1} = data{i};
disp(done);
end
end
w = xlswrite('data.xlsx',done','E2:E400');
Ok that helps I am aware the cell array's are larger than 3 cell range. I am trying to get the Nx1 cell array to fit into one cell in Excel because It needs to correspond to information in an adjacent cell. Is this at all possible to do?
A B C D E
w Rv0146 na Rv0039c (i want the cell array1 to go here)
s Rv0156 na Rv0029c (i want the cell array2 to go here)
s Rv0156 na Rv0029c (i want the cell array2 to go here)
Here is what I am looking to do in excel
UPDATED ANSWER:
If I understand correctly, it appears that your variable data is a cell array where each cell contains a 1-by-N (or perhaps N-by-1) cell array of strings. If you want to try and fit each of these cell arrays of strings into one cell of a spreadsheet, you are going to need to format each into a single long string first.
Here's an example of how you could format the cell arrays of strings by concatenating them together with a newline between them:
data = {{'hello' 'hi' 'hey'} ... %# Sample cell array of 1-by-N
{'world' 'earth' 'everyone'} ... %# cell arrays of strings
{'blah' 'blah'}};
data = cellfun(#(x) {strcat(x,{char(10)})},data); %# Add newline characters
%# to the string ends
data = cellfun(#(x) {deblank([x{:}])},data); %# Concatenate the inner cells and
%# remove the trailing newlines
Now that each cell array of strings is just a single long string, each string can be written to a cell of an Excel spreadsheet as follows:
xlswrite('data.xls',data(:),'Sheet1','E2'); %# Write the data to cells E2 to E4
And here's what the resulting spreadsheet looks like:
If you use a space ' ' instead of a newline character, here's what the spreadsheet looks like (after adjusting the row and column widths):
Functions used in the above code: CELLFUN, STRCAT, CHAR, DEBLANK, XLSWRITE.

Resources