user1360006
user1360006

Reputation: 11

Most efficient way to split a 2D array?

I am trying to read a file into a global array, loop through the array and identify each string to it's corresponding amount, and then find the sums in their own groups. and divide those groups each by their own unique number.

The text file that I am reading in:

Name,50
Name,40
DifferentName,50
AnotherName,10
Name,60

What would be the easiest way to split the lines at the commas, and make the numbers correspond to their specific names, not knowing which order they will be in?

Here is the code I am using so far..although right now it is just the open file dialog, I am putting this here as a constructive reference.

        string strFileName;

    private void btnReadInFile_Click(object sender, EventArgs e)
    {
        //select the file
        OpenFileDialog ofdGetFile = new OpenFileDialog();
        if (ofdGetFile.ShowDialog() == DialogResult.Cancel)
        {
            //cancel
            MessageBox.Show("User Canceled");
            return;
        }
        else
        {
            //open the file
            StreamReader myStreamReader;
            strFileName = ofdGetFile.FileName;
            FileStream input = new FileStream(strFileName, FileMode.Open, FileAccess.Read);
            myStreamReader = new StreamReader(input);
            // other
            MessageBox.Show("Reading Complete", "Done!", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
    }

    private void btnShowGrade_Click(object sender, EventArgs e)
    {
        if (strFileName != null)
        {
            String[][] nameSums = System.IO.File.ReadLines(strFileName)
           .Select(l => l.Split(','))                // split the line
           .GroupBy(arr => arr[0])                   // group by name
           .Select(grp => new String[]{
            grp.Key,
            grp.Sum(arr => int.Parse(arr[1])).ToString()})
           .ToArray();

        }
        else
        {
            MessageBox.Show("You need to read in a file first.");
        }
    }
}

I feel like there has to be a better way to do this.

Thank you all so much for your help thus far! I am sure that the only reason this problem hasn't been resolved is my lack of communication skills.

Upvotes: 0

Views: 6343

Answers (4)

Tim Schmelter
Tim Schmelter

Reputation: 460228

Edit according to your last edit:

identify each string to it's corresponding amount, and then find the sums in their own groups

It's still not clear what you want to achieve. You should have provided the desired result of your sample data. I assume the amount is the number and group is the name-group.

So for the Name-group it would be 50+40+60=150, DifferentName=50 and AnotherName=10?

This creates a Dictionary of unique names and their according amounts:

Dictionary<String, int> nameSums = 
      System.IO.File.ReadLines(path)  // read lines from file
     .Select(l => l.Split(','))       // split the line
     .GroupBy(arr => arr[0])          // group by name
     .ToDictionary(grp =>  grp.Key, grp => grp.Sum(arr => int.Parse(arr[1])));

If you insist on an array approach, following creates and initializes a jagged array(array of arrays) with the name as first element and the sum as second:

String[][] nameSums = System.IO.File.ReadLines(path)  // read lines from file
            .Select(l => l.Split(','))                // split the line
            .GroupBy(arr => arr[0])                   // group by name
            .Select(grp => new String[]{
                grp.Key,
                grp.Sum(arr => int.Parse(arr[1])).ToString()})
            .ToArray();

first approach:

"make the numbers correspond to their specific names"

So i assume that you want the names that belong to each number. If this is true a Dictionary<String, List<String>> would be the best choice:

var numNames = System.IO.File.ReadLines(path)
    .Select(l => l.Split(','))
    .GroupBy(arr => arr[1])
    .ToDictionary(grp => grp.Key, grp => grp.Select(arr => arr[0]).ToList());
  1. The lines are read from file as IEnumerable<String>
  2. then each line is split by comma to a String[]
  3. these are grouped by the second element(the number) to get unique numbers and their names
  4. the result will be used to create a Dictionary, the (now) unique numbers are the keys and the names are the values as List<String>

If you aren't familiar with dictionaries, you normally access them by the key, so if you want to know all names for the number "50":

List<String> names = numNames["50"];
foreach(String name in names)
    Console.Write("name={0}", name);

Or if you want to iterate all:

foreach(var numName in numNames)
    foreach(var name in numName.Value)
        Console.Write("number={0} name={1}", numName.Key, name);

Upvotes: 1

Phillip Schmidt
Phillip Schmidt

Reputation: 8818

Why not use a Dictionary?

So,

Dictionary<string,int> namesAndAges = new Dictionary<string,int>();
String[] line = new String[2];
while(there's still xml to read)
    {
        aLineOfXml = blah; //read a line of xml however you were gonna do it 
        line = aLineOfXml.Split(',');
        namesAndAges.Add(line[0],line[1]);
    }

The first two lines in the while loop would be better condensed into one, but for clarity and because I didn't want to add any xml parsing code, i split it like that.

Upvotes: 0

Lukasz Madon
Lukasz Madon

Reputation: 15004

Your task is IO bound. Most likely you won't gain any benefit changing the code. Firstly, you should use profiler to find the bottleneck of your application.

If you have .Net 4, 4.5 or Silverlight use ReadLines method. It returns an iterator that represents a collection of lines. Snippet:

        List<KeyValuePair<string, double> values = new List<KeyValuePair<string, double>();
        var lines = File.ReadLines(myFile);
        foreach (var line in lines)
        {
            var data = line.Split(',');
            var x = data[0];
            var y = Double.Parse(data[1], CultureInfo.InvariantCulture);
            var pair = new KeyValuePair<string, double>(x, y);
            values .Add(pair);
        }

Upvotes: 0

Yuriy Faktorovich
Yuriy Faktorovich

Reputation: 68707

myArray = File.ReadAllLines(myFileName).Select(l => l.Split(',')).ToArray();

Note this will be a staggered array, not a 2 dimensional one. To create a 2 dimensional one, you could use

lines = File.ReadAllLines(myFileName).Select(l => l.Split(',')).ToArray();
myArray = new string[lines.Count(), 2];
for(int i = 0; i < lines.Length; i++)
{
    myArray[i, 0] = lines[i, 0];
    myArray[i, 1] = lines[i, 1];
}

Upvotes: 0

Related Questions