Home > Mobile >  Populating a 2D Matrix of List<string> from csv
Populating a 2D Matrix of List<string> from csv

Time:11-12

I have a matrix of routes stored into a csv from a pandas dataframe. The content of this csv looks like:

,hA,hB,hC
hA,[],["hA","hB"],["hA","hB","hC"]
hB,["hB","hA"],[],["hB","hC"]
hC,["hC","hB","hA"],["hC","hB"],[]

From this file I would like to generate a matrix in c#, so I could get the route from hA to hC with something like:

routes["hA"]["hC"]

I can achieve this generating manually a Dictionary<string, Dictionary<string, List<string>>> like:

Dictionary<string, Dictionary<string, List<string>>> routes = new Dictionary<string, Dictionary<string, List<string>>>(){
                {"hA", new Dictionary<string, List<string>>(){ { "hA", new List<string>() }, {"hB", new List<string>() { "hA", "hB" }}, { "hC", new List<string>() { "hA", "hB", "hC" }}}},
                { "hB", new Dictionary<string, List<string>>() { { "hA", new List<string>() { "hB", "hA" }}, { "hB", new List<string>() { }, { "hC", new List<string>() { "hB", "hC" }}}},
                { "hC", new Dictionary<string, List<string>>() { { "hA", new List<string>() { "hC", "hB", "hA" }}, { "hB", new List<string>() { "hC", "hB" }}, { "hC", new List<string>() { } }}}
            };

But in case the size of the matrix increases or everytime a route changes it is a lot of reworking involved. Thant is why I could like to populate the routes matrix from the csv directly

Is there any way of populating this matrix from a csv? or is it a better type of collections to store this routes instead of Dictionary<string, Dictionary<string, List<string>>>?

CodePudding user response:

Oof.. I think I'd read that CSV with a parser library set to use [ and ] as "quote" chars, but this will read it simplistically:

var lines = File.ReadAllLines(path);

var cols = lines[0].Split(',');

var frame = new Dictionary<string, Dictionary<string, string[]>>();

foreach(var line in lines.Skip(1)){

  var bits = line.Replace("]", "").Split(",[");

  var row = bits[0];

  for(int i = 1; i < cols.Length; i  ){
    var col = cols[i];
    
    frame.TryAdd(row, new Dictionary<string, string[]>());

    frame[row][col] = bits[i].Split(',').Select(s => s.Trim('"')).ToArray(); 
  }
}

That should deliver you your nested dictionaries so you can address them like you would a dataframe.. By the way, I don't know what happens if you ask a dataframe for something that isn't there, but c# would throw a KeyNotFoundException if you asked for eg frame["hZ"]["hello"] ..

If you want the innermost storage container to be a List you can swap the ToArray to be ToList

You perhaps don't need to nest, by the way:

var frame = new Dictionary<(string, string), string[]>();

foreach(var line in lines.Skip(1)){

  var bits = line.Replace("]", "").Split(",[");

  var row = bits[0];

  for(int i = 1; i < cols.Length; i  ){
    var col = cols[i];
    
    frame[(row, col)] = bits[i].Split(',').Select(s => s.Trim('"')).ToArray(); 
  }
}

It could be queried like frame[("hA","hB")]

CodePudding user response:

Turn your node names (ie, hA, hB, hC) into an enum:

enum Indexer {
    hA = 0,
    hB = 1,
    hC = 2
}

Use a two-dimensional array of lists:

List<string>[,] Matrix = new List<string>[3,3];

Access the data out of the Matrix:

List<string> path = Matrix[(int)Indexer.hA, (int)Indexer.hC];

If you need to, you can convert the text-based node names back to an enum:

var n = (Indexer)Enum.Parse(typeof(Indexer), "hA");

This assumes that you are importing a csv of pre-defined node names. Let me know if the node names can't be pre-defined and I'll update the answer.

CodePudding user response:

Based on @CaiusJard and @derHugo suggestions

I needed to modify a little bit the original csv file to make it easier by removing the first column (which cointaed the index) and using ";" as column separator df_routes.to_csv("routes_mtrx_headers.csv", sep = ';', index = False)

The final solution is

var route_dictionary = new Dictionary<(string, string), string[]>();

using (var reader = new StreamReader(@"C:/mypath/myfile.csv"))
{
    string[] locations = reader.ReadLine().Split(';');
    int rowIdx = 0;
    int colIdx = 0;

    while (!reader.EndOfStream)
    {
        var row = reader.ReadLine();
        var columns = row.Split(';');
        colIdx = 0;

        foreach (var col in columns)
        {
            // Removing the List wrapper
            var path = col.Replace("]", "").Replace("[", "").Split(',');
            route_dictionary.Add((locations [colIdx], locations [rowIdx]), path);
            colIdx  = 1;
        }
        rowIdx  = 1;
    }
}

# Finally to access each element in the matrix
var route = route_dictionary[("hA", "hC")]; 
  • Related