0

I have a csv file with repetitive keys and multiple values from a csv. I have successfully parsed every row of csv in C#

My csv file looks like this

eid,hr
ABC,25
ABC,35
FDG,50
LMN,61

Task1 I would want to construct a dictionary

like Dictionary<string,int[]> or Dictonary<string,List>

key1: ABC value1: 25
key2: ABC value2: 35
key3: FDG value3: 50
key4: LMN value4: 61

Task 2

Iterate through keys and make sure the total of the values for the same key is more than 50. value1 and value2 will be proportioned to make the total as 50.

Here is the solution:

    namespace CSVRead {class Program
    {
        static void Main(string[] args)
        {
            
            string[] csvLines = System.IO.File.ReadAllLines("//TheCSVfilepath");

            var eID = new List<string>();
            var hr = new List<double>();


            for ( int i = 1; i < csvLines.Length; i++)
            {
                string[] rowData = csvLines[i].Split(',');

                eID.Add(rowData[0]);

                double hre = Convert.ToDouble(rowData[7]);
                hr.Add(hre);
             

            }

            Console.WriteLine("eidDict:  ");
            for ( int m =0 ; m < eID.Count ; m++)
            {
                List<(string Key, double Value)> list = new List<(string Key, double Value)>; //CS1526Error
                var eIDdictlist = list;

                for (int n =0; n < hr.Count; n++)
                {
                    employedictlist.Add(new KeyValuePair<string, double>(eID[m], hr[n])); //CS1503 Error
                    Console.WriteLine(eIDdictlist);
                }
            }

            Console.ReadKey();

        }
    }
5
  • What did you try yourself? Commented Oct 22, 2021 at 16:49
  • 1
    stackoverflow.com/q/146204 Commented Oct 22, 2021 at 16:49
  • Your code doesn't compile. Are you just trying to get it to compile? Commented Oct 22, 2021 at 17:36
  • @NigelBess I have edited my question and I am trying to compile. Please let me know Commented Oct 22, 2021 at 17:38
  • 1
    A "dictionary" with multiple values per key is called a Lookup. You can create one from an IEnumerable using ToLookup. Commented Oct 22, 2021 at 17:48

2 Answers 2

1

Your code doesn't seem to do remotely what your question is asking about. Here's what you need to do to get a dictionary of the list of values:

     static void Main(string[] args)
    {

        var csvLines = File.ReadAllLines("//TheCSVfilepath");

        var dictionary = new Dictionary<string, List<double>>();
        foreach (var line in csvLines)
        {
            var (eID, hr) = GetEidAndHr(line);
            if (!dictionary.TryGetValue(eID, out var hrList))
            {
                hrList = new List<double>();
                dictionary[eID] = hrList;
            }

            hrList.Add(hr);
        }

        Console.WriteLine("eidDict:  ");
        //foreach (var keyValuePair in dictionary) // for pre c# 8
        foreach (var (eid,hrList) in dictionary)
        {
           // var eid = keyValuePair.Key;// for pre c# 8
           // var hrList = keyValuePair.Value;// for pre c# 8
            var sum = hrList.Sum();
            Console.WriteLine($"{eid}, {sum}");
        }
    }

    static Tuple<string, double> GetEidAndHr(string csvLine)
    {
        var rowData = csvLine.Split(',');
        return new Tuple<string, double>(rowData[0],double.Parse(rowData[7]));
    }

If you are just trying to get your code to compile, here is what you need to change:

List<(string Key, double Value)> list = new List<(string Key, double Value)>; //CS1526Error

Needs to become

List<(string Key, double Value)> list = new List<(string Key, double Value)>();

And you also need to declare your variable employedictlist before you use it.

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

9 Comments

Thanks Nigel for sharing the answer. Unfortunately I get 4 errors: CS8129- No suitable 'Deconstruct' instance or extension method was found for type 'KeyValuePair<string, List<double>>', with 2 out parameters and a void return type,CS1061-- 'KeyValuePair<string, List<double>>' does not contain a definition for 'Deconstruct' and no accessible extension method 'Deconstruct' accepting a first argument of type 'KeyValuePair<string, List<double>>' could be found (are you missing a using directive or an assembly reference?)=
@exdas that just means your C# language version is set to something before C# 8.0. I updated my answer with some commented lines that you can use for C#7 or earlier
Also, the foreach loop has typo eid must eID
return new Tuple<string, double>(rowData[0], double.Parse(rowData[6])); >>>> System.FormatException: 'Input string was not in a correct format.' ??. Please help . Thanks Nigel . I appreciate this
whatever row you were on did not have 8 or more items. I just used the indexing you provided which optimistically assumes at least 8 items per row. You will need to decide on your own what happens when a row has less than 8 items.
|
0

I think the following code should work for you:

// Test data to mock data from the CSV file
static IEnumerable<(string key, double value)> ReadCsv() =>
    new[]
    {
        ("ABC", 42.0),
        ("ABC", 123.0),
        ("DEF", 35.0),
        ("DEF", 15.0)
    };

static void Main(string[] args)
{
    // Task 1: Constructing a Dictionary<string, List<double>>
    var data = ReadCsv()
        .GroupBy(entry => entry.key)
        .ToDictionary(
            group => group.Key,
            group => group.Select(entry => entry.value));

    // Task 2: Iterating through the keys and verifying the total
    var isSuccess = data.All(entry => entry.Value.Sum() > 50);
    if (isSuccess)
        Console.WriteLine("The total of values for each and every entry is greater than 50");
    else
        Console.WriteLine("The total of values for each and every entry is not greater than 50");
}

To read data from a CSV file, I would suggest using something like:

static IEnumerable<(string key, double value)> ReadCsv(string filePath, uint nHeaderLines = 0)
{
    using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
    using (var reader = new StreamReader(stream))
    {
        var lineIndex = 0u;
        while (reader.ReadLine() is string dataEntry)
        {
            if (lineIndex++ < nHeaderLines                // Skip header
                || string.IsNullOrWhiteSpace(dataEntry))  // Ignore blank lines
            {
                continue;
            }

            var dataElements = dataEntry.Split(',', StringSplitOptions.RemoveEmptyEntries);
            var key = dataElements[0];
            var value = double.Parse(dataElements[7], NumberStyles.Float, NumberFormatInfo.InvariantInfo);

            yield return (key, value);
        }
    }
}

Please note, that for the real solution it would also make sense to check the data line if it has all the entries, i.e., that elements at index 0 and 7 always exist and are valid

11 Comments

Could you please let me know what is the issue ?? Exception Unhandled: System.FormatException : " Input string was not in a correct format ."
@exdas First thing you can try is to change the parsing line to var value = double.Parse(dataElements[7], NumberStyles.Float, NumberFormatInfo.InvariantInfo);. If this does not work, you can try var value = Convert.ToDouble(dataElements[7]);. If this does not work too, please provide the sample value in your dataElements[7] entry in a comment. I updated the sample code.
@exdas The issue is that dataElements[7] with the data sample you provided would have a value of AB-564-611, which is definitely not a double. What value (or what index) from the data entry do you want to have in the output? Or does the CSV file contain a header line that has to be skipped and the data follow in the next rows?
@exdas I modified the ReadCsv(...) method to take into account header and blank lines. Please make sure you are parsing the data at the correct indices. If you want to parse data from eid and hr XXX1023 columns, you shall take dataElements[0] and dataElements[6], not dataElements[7]. Hope this helps.
@exdas dataEntry is a string that represents a single line of data that is being read from a CSV file. It's set in the while (reader.ReadLine() is string dataEntry) loop. The loop will read the file line by line until it reaches its end.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.