1

as the title suggests, I am looking for guidance in how to turn a string (csvData) into a 2D string array by splitting it two times with ';' and ',' respectivly. Currently I am at the stage where I am able to split it once into rows and turn it into an array, but I cannot figure out how to instead create a 2D array where the columns divided by ',' are also separate.

string[] Sep = csvData.Split(';').Select(csvData => csvData.Replace(" ","")).Where(csvData => !string.IsNullOrEmpty(csvData)).ToArray();

I have tried various things like :

string[,] Sep = csvData.Split(';',',').Select(csvData => csvData.Replace(" ","")).Where(csvData => !string.IsNullOrEmpty(csvData)).ToArray();

naivly thinking that c# would understand what I tried to achieve, but since I am here it's obvious that I got the error that "cannot implicitly convert type string[] to string [*,*]"

Note that I have not coded for a while, so if my thinking is completely wrong and you do not understand what I am trying to convey with this question, I apologize in advance. Thanks!

0

4 Answers 4

1

In a strongly-typed language like C#, the compiler makes no assumptions about what you intend to do with your data. You must make your intent explicit through your code. Something like this should work:

string csvData = "A,B;C,D";
string[][] sep = csvData.Split(';') // Returns string[] {"A,B","C,D"}
  .Select(str => str.Split(',')) // Returns IEnumerable<string[]> {{"A","B"},{"C","D"}}
  .ToArray(); // Returns string[][] {{"A","B"},{"C","D"}}
Sign up to request clarification or add additional context in comments.

3 Comments

There's a difference between [,] and [][].
@Enigmativity I know, but I don't know if there's any way to turn an IEnumerable<T[]> into a T[,] using idiomatic Linq.
No, there is not.
1

Rows are separated by semicolon, columns by comma?

Splitting by ';' gives you an array of rows. Split a row by ',' gives you an array of values.

If your data has a consistent schema, as in each csv you process has the same columns, you could define a class to represent the entity to make the data easier to with with.

Let's say it's customer data:

John,Smith,8675309,[email protected];

You could make a class with those properties:

public class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Phone { get; set; }
    public string Email { get; set; }
}

Then:

var rows = csvdata.Split(';');
List<Customer> customers = new();
foreach(var row in rows)
{
    var customer = row.Split(',');
    customers.Add(new()
    {
        FirstName = row[0],
        LastName = row[1],
        Phone = row[2],
        Email = row[3]
    });
}

Now you have a list of customers to do whatever it is you do with customers.

4 Comments

I was really stuck to the idea of using a 2D array, but with this example it may result to a cleaner solution using a list instead. Thanks a lot!
@LePelican - Are you saying that you did not specifically want to create a 2d array? You just needed to parse your input into a list?
@Enigmativity Yes, that was indeed the case. But as I stated, I have been away from programming for a hot minute and therefore stared myself blind to the idea of expanding the array which I had created initially into a 2D array instead of simply creating a list. I really do appriciate your answer above though as it gave me insight on how to proceed when I do need a 2D array! Thanks, and sorry for the confusion on my behalf!
@LePelican, his answer would be a good approach if your data was not consistent.
1

Here is an answer to present a few alternative ideas and things you can do with C# - more for educational/academic purposes than anything else. These days to consume a CSV we'd use a CSV library


If your data is definitely regularly formed you can get away with just one Split. The following code splits on either char to make one long array. It then stands to reason that every 4 elements is a new customer, the data of the customer being given by n+0, n+1, n+2 and n+3. Because we know how many data items we will consume, dividing it by 4 gives us the number of customers so we can presize our 2D array

var bits = data.Split(';',',');
var twoD = new string[bits.Length/4,4];
for(int x = 0; x < bits.Length; x+=4){
    twoD[x/4,0] = bits[x+0];
    twoD[x/4,1] = bits[x+1];
    twoD[x/4,2] = bits[x+2];
    twoD[x/4,3] = bits[x+3];
}

I don't think I'd use 2D arrays though - and I commend the other answer advising to create a class to hold the related data; you can use this same technique

var custs = new List<Customer>();
for(int x = 0; x < bits.Length;){
    custs.Add(new()
    {
        FirstName = bits[x++],
        LastName = bits[x++],
        Phone = bits[x++],
        Email = bits[x++]
    });
}

Here we aren't incrementing x in the loop header; every time a bit of info is assigned x is bumped up by 1 in the loop body. We could have kept the same approach as before, jumping it by 4 - just demoing another approach that lends itself well here.


I mentioned that these days we probably wouldn't really read a csv manually and split ourselves - what if the data contains a comma, or a semicolon - it wrecks the file structure

There are a boatload of libraries that read CSV files, CsvHelper is a popular one, and you'd use it like:

using var reader = new StreamReader("path\\to\\file.csv");
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture)

var custs = csv.GetRecords<Customer>().ToList();

...

Your file would have a header line with column names that match your property names in c#. If it doesn't then you can use attributes on the properties to tell CsvH what column should be mapped to what property - https://joshclose.github.io/CsvHelper/getting-started/

2 Comments

Amazing, well explained response which confirms the fact that going with a List should be the best option for me on this one! I'll also take a look at CsvHelper!
Welcome. One of the benefits of the likes of CsvH is you can make your Customer class properties other datatypes too; Age as int, Birthdate as DateTime, Weight as double etc, and (mostly) CsvH will do the conversion (you might just have to e.g. specify the date format in an attribute) so your reader code doesn't end up with a lot of messy parsing in too
1

Here's the simplest way I know to produce a 2d array by splitting a string.

string csvData = "A,B,C;D,E,F,G";

var temporary =
    csvData
        .Split(';')
        .SelectMany((xs, i) => xs.Split(',').Select((x, j) => new { x, i, j }))
        .ToArray();
        
int max_i = temporary.Max(x => x.i);
int max_j = temporary.Max(x => x.j);

string[,] array = new string[max_i + 1, max_j + 1];

foreach (var t in temporary)
{
    array[t.i, t.j] = t.x;
}

I purposely chose csvData to be missing a value.

temporary is this:

temporary

And the final array is this:

array

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.