mahalex / MatFileHandler

MATLAB .mat-file reading/writing API for .NET Standard
MIT License
40 stars 12 forks source link

How to get string values out of a cell array? #8

Closed patrickmcdermo closed 5 years ago

patrickmcdermo commented 5 years ago

I'd like to get the string values out of a cell array, but I cannot see how. Here's my code and I'm attaching a screenshot of the command prompt output.

using MatFileHandler;

namespace MatLabFiles.Header { class Program2 { private const string FilePath = "C:\Data\ImportFiles\CMI\Test_20190225\nn01_Bin1_cnnClass_Elephant_Multi_16Aug18_V7.mat";

    static void Main(string[] args)
    {
        IMatFile matFile;
        using (var fileStream = new System.IO.FileStream(FilePath, System.IO.FileMode.Open))
        {
            var reader = new MatFileReader(fileStream);
            matFile = reader.Read();
        }

        IVariable var2 = matFile["clab"];
        Console.WriteLine(var2.Name.ToString());
        Console.WriteLine(var2.GetType());

        IArray arr = var2.Value;

        Console.WriteLine(arr.Count.ToString());
        Console.WriteLine(arr.ToString());
        Console.WriteLine(arr.Dimensions);
        Console.ReadKey();
    }
}

} VariableArrayOutput

mahalex commented 5 years ago

Continuing your example, you can get values that are inside your cell array by casting to the ICellArray interface and using the indexer:

ICellArray cellArray = arr as ICellArray;
IArray value1 = arr[0];
IArray value2 = arr[1];

(you already know there are two of them by looking at arr.Count). If you know that both of these values are strings (char arrays in MATLABspeak), you can cast them to ICharArray and extract the strings:

string string1 = (value1 as ICharArray).String;
string string2 = (value2 as ICharArray).String;

You can find more examples along the same lines in MatFileHandler.Tests/MatFileReaderTests.cs.

patrickmcdermo commented 5 years ago

Thanks, Mahalex! I really appreciate your help, but please bear with me as I am not very familiar with Matlab array types. I tried what you suggested, but I had to change from this: IArray value1 = arr[0];

To this: IArray value1 = cellArray[0]; I couldn't get your version to compile. The error I got was: "Cannot apply indexing with [] to type of IArray."

I was told that the values in the "clab" variable were strings, but when I try to cast them as such, I get a System.NullReferenceException. I am interpreting this to mean that the cast is not successful and so is returning a NULL. Here's my code so far:

`using System; using MatFileHandler;

namespace MatLabFiles.Header { class Program2 { private const string FilePath = "C:\Data\ImportFiles\CMI\Test_20190225\nn01_Bin1_cnnClass_Elephant_Multi_16Aug18_V7.mat";

    static void Main(string[] args)
    {
        IMatFile matFile;
        using (var fileStream = new System.IO.FileStream(FilePath, System.IO.FileMode.Open))
        {
            var reader = new MatFileReader(fileStream);
            matFile = reader.Read();
        }

        IVariable var2 = matFile["clab"];

        IArray arr = var2.Value;

        Console.WriteLine(arr.Count.ToString());
        Console.WriteLine(arr.ToString());

        ICellArray cellArray = arr as ICellArray;

        IArray value1 = cellArray[0];
        IArray value2 = cellArray[1];

        Console.WriteLine(value1.Count);
        Console.WriteLine(value2.Count);

        string string1 = (value1 as ICharArray).String;
        string string2 = (value2 as ICharArray).String;

        Console.WriteLine(value1.ToString());
        Console.WriteLine(value2.ToString());

        Console.ReadKey();
    }
}

} ` Error at Console.WriteLine(value1.ToString()); System.NullReferenceException HResult=0x80004003 Message=Object reference not set to an instance of an object.

mahalex commented 5 years ago

Yes, you are right about cellArray instead of arr. From what I see, it looks like the values in your cell array are not strings (at least not in the traditional MATLAB sense of char arrays). Can you look at cellArray[0].GetType()? This would give a hint about what kind of object is there. If you want, you can send me the file that you are inspecting, and I'll take a look at it myself.

patrickmcdermo commented 5 years ago

Thanks! When I get the type of cellArray[0] it returns MatFileHandler.MatCellArray. So it must be a cell array, inside a cell array. I'm guessing the string values are in the inner cell array. Is that possible? I'll check with the creator of the file.

mahalex commented 5 years ago

Yes, cell arrays may contain nested cell arrays; you can treat them in a similar way to access their elements and inspect their types. Standard MATLAB strings should look like MatCharArrayOf<byte> or MatCharArrayOf<ushort>.

patrickmcdermo commented 5 years ago

Thank you! I can now see the MatCharArrayOf1[System.Byte]. I still need to get the actual strings that are inside of that. Here's my code so far: static void Main(string[] args) { IMatFile matFile; using (var fileStream = new System.IO.FileStream(FilePath, System.IO.FileMode.Open)) { var reader = new MatFileReader(fileStream); matFile = reader.Read(); }

        IVariable var2 = matFile["clab"];

        IArray arr = var2.Value;

        Console.WriteLine(arr.Count.ToString());
        Console.WriteLine(arr.ToString());

        ICellArray cellArray = arr as ICellArray;

        IArray value1 = cellArray[0];
        IArray value2 = cellArray[1];

        Console.WriteLine(cellArray[0].GetType());

        ICellArray cellArray1 = value1 as ICellArray;
        ICellArray cellArray2 = value2 as ICellArray;

        IArray valA = cellArray1[0];
        IArray valB = cellArray2[1];

        Console.WriteLine(value1.Count);
        Console.WriteLine(value2.Count);

        Console.WriteLine(valA.Count);
        Console.WriteLine(valB.Count);

        string string1 = (valA as ICharArray).String;
        string string2 = (valB as ICharArray).String;

        Console.WriteLine(valA.ToString());
        Console.WriteLine(valB.ToString());

        Console.ReadKey();
    }`

And this is what it returns: image