Click here to Skip to main content
15,902,635 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
if I have a file:

name    state      ClosetSize    childGender
Hank    OK         2               M
Hank    OK         1               F
Wilbur  TX         1               F
Wilbur  TX         2               F
Tom     CA         3               M
Tom     CA         4               M
Zed     VT         1               M
Zed     VT         2               M
Zed     VT         3               F


I want to output a file if the combined total closet size of only the people that has BOTH at least one female (F) and at least one (M). Then output that to another csv. file.

I would expect that to be only Hank and Zed

What I have tried:

I've tried loading this into a list and using Linq
Posted
Updated 7-Nov-17 6:07am
v2
Comments
Richard Deeming 6-Nov-17 16:01pm    
Where's the code you've tried, and what was the problem with it?
Member 13506556 6-Nov-17 17:40pm    
looking for a good structure to begin. Load, aggregate, export. I don't have a viable starting point.

try

DataTable dt = new DataTable();
           dt.Columns.Add("name");
           dt.Columns.Add("state");
           dt.Columns.Add("ClosetSize");
           dt.Columns.Add("childGender");
           dt.Rows.Add("Hank", "OK", 2, "M");
           dt.Rows.Add("Hank", "OK", 1, "F");
           dt.Rows.Add("Wilbur", "tx", 1, "F");
           dt.Rows.Add("Wilbur", "tx", 2, "F");
           dt.Rows.Add("Tom", "ca", 3, "M");
           dt.Rows.Add("Tom", "ca", 4, "M");
           dt.Rows.Add("Zed", "VT", 1, "M");
           dt.Rows.Add("Zed", "VT", 2, "M");
           dt.Rows.Add("Zed", "VT", 3, "F");

           DataTable dtOutput = dt.Clone();
           string[] names = dt.Rows.OfType<DataRow>().Select(k => k["name"] + "").Distinct().ToArray();
           foreach (string name in names)
           {
               var tempRows = dt.Select("name='" + name + "'");
               if (tempRows.Length > 1)
               {
                   string[] genders = tempRows.Select(k => k["childGender"] + "").Distinct().ToArray();
                   if (genders.Contains("M") && genders.Contains("F"))
                       foreach (DataRow row in tempRows)
                           dtOutput.Rows.Add(row.ItemArray);
               }
           }


refer this to convert csv to datatable and vice versa
Read CSV File into Data Table[^]
Export Datatable to CSV Using Extension Method[^]
 
Share this answer
 
v2
Another option, using CsvHelper[^]:
C#
struct SourceRecord
{
    public string name { get; set; }
    public string state { get; set; }
    public int ClosetSize { get; set; }
    public char childGender { get; set; }
    
    public static IReadOnlyCollection<SourceRecord> Load(TextReader reader)
    {
        var csv = new CsvReader(reader);
        return csv.GetRecords<SourceRecord>().ToList();
    }
    
    public static IReadOnlyCollection<SourceRecord> LoadFrom(string fileName)
    {
        using (var reader = File.OpenText(fileName))
        {
            return Load(reader);
        }
    }
}

struct OutputRecord
{
    public string name { get; set; }
    public string state { get; set; }
    public int ClosetSize { get; set; }
    
    public static void Save(TextWriter writer, IEnumerable<OutputRecord> records)
    {
        var csv = new CsvWriter(writer);
        csv.WriteRecords(records);
    }
    
    public static void SaveTo(string fileName, IEnumerable<OutputRecord> records)
    {
        using (var writer = new StreamWriter(fileName))
        {
            Save(writer, records);
        }
    }
}

static void Process(string inputFile, string outputFile)
{
    IReadOnlyCollection<SourceRecord> input = SourceRecord.LoadFrom(inputFile);
    
    IEnumerable<OutputRecord> output = input
        .GroupBy(r => new { r.name, r.state })
        .Where(g => g.Any(r => r.childGender == 'M') && g.Any(r => r.childGender == 'F'))
        .Select(g => new OutputRecord
        {
            name = g.Key.name,
            state = g.Key.state,
            ClosetSize = g.Sum(r => r.ClosetSize),
        });
    
    OutputRecord.SaveTo(outputFile, output);
}

Output:
name,state,ClosetSize
Hank,OK,3
Zed,VT,6
 
Share this answer
 
Comments
Member 13506556 7-Nov-17 12:07pm    
this looks like something I can work with. I only am running into an error on the line:
return csv.GetRecords<sourcerecord>().ToList();


Error CS1061 'object' does not contain a definition for 'ToList' and no extension method 'ToList' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?

I am including using system.Linq;
Richard Deeming 7-Nov-17 12:28pm    
It works fine for me: Demo[^]
Member 13506556 7-Nov-17 13:36pm    
got it. Thanks!

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900