0

I am reading in a csv file that I would like to add the second column into the same list as a column that match the name. I check the the next line is equal to the previous record but then I loop the array finding the match but I am not sure how to add that internalList back into the class object.

is there a better way to do this?

Program

while ((s = sr.ReadLine()) != null)
{
string[] words = s.Split('\t');

if (previousrecord == words[0])
{
    for (int i = 0; i < ALEComName.Count; ++i)
        {

        }
}
else
{
    Name person = new Name();
    person.Name = words[0];
    List<SubName> internalList = new List<SubName>();
    SubName AssociatedSub = new SubName { Name = words[1] };
    internalList.Add(AssociatedSub);
    person.AssociatedSub = internalList;
    ALEComName.Add(Disease);
}
previousrecord = words[0];

Dto

    public class Name
    {

        public string Name { get; set; }

        public List<SubName> AssociatedSub { get; set; }
    }

    public class SubName
    {

        public string Name { get; set; }

    }
}

CSV File

A   A
B   B
C   A
C   B
C   C
D   A
D   B

2 Answers 2

1

You can read all lines, then use Linq:

var data = File.ReadAllLines(@"c:\temp\sample.txt");
var names = data.Select(d => d.Split('\t'))
.Select(s => new { Name = s[0], SubName = s[1] })
.GroupBy(o => o.Name)
.Select(g => new Name()
{
    Name1 = g.Key,
    AssociatedSub = g.Select(v => new SubName() { Name = v.SubName }).ToList()
});

//This part is just to show the output
foreach (var name in names)
{
    Console.WriteLine($"Name: {name.Name1}, AssociatedSub: {string.Join(",", name.AssociatedSub.Select(s => s.Name).ToArray())}");
}

Output:

Name: A, AssociatedSub: A

Name: B, AssociatedSub: B

Name: C, AssociatedSub: A,B,C

Name: D, AssociatedSub: A,B

I had to change the name of the property to Name1 since it's an invalid language construct.

You first select the result of the split, then create an anonymous type with Name and SubName properties that will be used for grouping. Lastly, you select from the grouped results and create the instances.

This is just a quick sample so be careful for errors such as the Split not returning the expected numbers of parts.

Sign up to request clarification or add additional context in comments.

Comments

0

The Linq approach is very nice, I agree with the idea. I made a dictionary approach in case you wanted a more conservative way, which stores key,value pairs.

class Program {
        static void Main(string[] args) {

            using(var file = new StreamReader(@"../file.csv")) {
                var dict = new Dictionary<string, List<string>>();
                List<string> split;
                string line, key;

                while((line = file.ReadLine()) != null) {
                    split = line.Select(l => new string(l, 1)).Where(l => l != " ").ToList();
                    key   = split[0];
                    split.RemoveAt(0);

                    if(dict.ContainsKey(key)) { 
                        dict.TryGetValue(key, out var values);
                        values.AddRange(split);
                    } else dict.Add(key, split);
                }

                foreach(KeyValuePair<string, List<string>> r in dict) {
                    foreach(var val in r.Value) {
                        Console.WriteLine("Main = {0}, Sub = {1}", r.Key, val);
                    }
                }
            }
        }
    }

Comments

Your Answer

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