1

I created a List<> of objects using info from productdetails.csv file and I have to update that List<> with info from salesdata.csv which I have currently stored in an array (5 int figures of quantities of sales) but I'm stumped as to how to do it. I added another constructor to the Product Class thinking that maybe I could create a new List<> of objects with the 'WeeklySales' property included... I have unfortunately not been able to find any enlightenment in other similar questions. Thanks in advance for any light you can shed on the subject.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace q6._2
{
class Program
{
    static void Main(string[] args)
    {
        string fileName = GetDataDirectory() + "\\data\\salesdata.csv";

        string[] salesDetails = File.ReadAllLines(fileName);
        string[] salesCol = new string[2];

        for (int i = 1; i < salesDetails.Length; i++)
        {
            string currentLine = salesDetails[i];

            salesCol = currentLine.Split(',');

            string salesQuant = salesCol[1];
        }

        Console.ReadLine();
    }



    public static string GetDataDirectory()
    {
        string path = Directory.GetCurrentDirectory();

        char[] removeSequence = { 'b', 'i', 'n', '\\', 'D', 'e', 'b', 'u', 'g' };
        string newPath = path.TrimEnd(removeSequence);

        return newPath;
    }



    public static List<Product> ReadProductFile()
    {
        string fileName = GetDataDirectory() + "\\data\\productdetails.csv";

        string[] productDetails = File.ReadAllLines(fileName);

        string[] lineDetails = new string[5];

        List<Product> productObj = new List<Product>();

        for (int i = 1; i < productDetails.Length; i++)
        {
            lineDetails = productDetails[i].Split(',');
            Product newProduct = new Product(lineDetails[0], lineDetails[1], lineDetails[2], Convert.ToDecimal(lineDetails[3]), Convert.ToInt32(lineDetails[4]));
            productObj.Add(newProduct);
        }

        return productObj;
    }
}

class Product
{
    public string ID { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }
    public int StockAvailable { get; set; }
    public int WeeklySales { get; set; }

    public Product(string id, string name, string description, decimal price, int stockavailable)
    {
        ID = id;
        Name = name;
        Description = description;
        Price = price;
        StockAvailable = stockavailable;
    }

    public Product(string id, string name, string description, decimal price, int stockavailable, int weeklysales)
    {
        ID = id;
        Name = name;
        Description = description;
        Price = price;
        StockAvailable = stockavailable;
        WeeklySales = weeklysales;
    }
}

}

13
  • I find it very hard to understand what your actual question is... is the code above (not) working? what is the problem? Commented Jan 15, 2015 at 11:51
  • A much smaller example will suffice to show your problem Commented Jan 15, 2015 at 11:52
  • 1
    Apologies Stephan. The code is working. I created a List of objects using productdetails.csv with the properties shown in first constructor. I need to update that List with the sales quantities from salesdata.csv. I read in the sales quantities from salesdata.csv but I'm unsure how to put these sales quantities into the List of objects I made called productObj. Commented Jan 15, 2015 at 11:56
  • I imagine you are right @DrKoch but I thought giving an overview might be more helpful. A rookie mistake I guess. Commented Jan 15, 2015 at 11:58
  • 2
    Splitting on comma is not how you read CSV lines and will break if your fields need to contain your separator. You might want to consider adding a reference to Microsoft.VisualBasic.dll and using Microsoft.VisualBasic.FileIO.TextFieldParser so that you don't get messed up by escape chars and other CSV gotchas. Yes... it works fine from C#. Commented Jan 15, 2015 at 12:03

2 Answers 2

1

This should be the answer.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace q6._2
{
    class Program
    {
        static void Main(string[] args)
        {
            // ReadProductFile() <- fills all the 
            List<Product> productContents = ReadProductFile();

            ReadSalesAndMergeWithProducts(ref productContents);

            foreach (Product p in productContents)
            {
                Console.WriteLine(p.ToString());
            }

            Console.ReadLine();
        }


        private static void ReadSalesAndMergeWithProducts(ref List<Product> productContents)
        {
            string[] salesDetails = File.ReadAllLines(GetDataDirectory() + "\\data\\salesdata.csv");
            int smallestNr = GetSmallestOfTwo(salesDetails.Length, productContents.Count);

            for (int i = 1; i < smallestNr; i++)
            {
                productContents.ElementAt(i).WeeklySales = Convert.ToInt32(salesDetails[i].Split(',')[1]);
            }
        }


        /// <summary>
        /// shortend GetDataDirectory
        /// </summary>
        /// <returns></returns>
        public static string GetDataDirectory()
        {
            return System.IO.Directory.GetCurrentDirectory().Replace("bin\\Debug", "");
        }


        /// <summary>
        /// ReadProductFile
        /// </summary>
        /// <returns>List<</returns>
        public static List<Product> ReadProductFile()
        {            
            // remove the filename string and directly pass it to the read all lines
            string[] productDetails = File.ReadAllLines(GetDataDirectory() + "\\data\\productdetails.csv");

            // no need to classify the size here since it will return from product details. (no harm though)
            string[] lineDetails;// = new string[5];

            // create a new product object
            List<Product> productObj = new List<Product>();

            // loop over the product details
            for (int i = 1; i < productDetails.Length; i++)
            {
                // split on comma char
                lineDetails = productDetails[i].Split(',');
                // create new product
                Product newProduct = new Product(lineDetails[0], lineDetails[1], lineDetails[2], Convert.ToDecimal(lineDetails[3]), Convert.ToInt32(lineDetails[4]));
                // add product to list
                productObj.Add(newProduct);
            }

            // return List<Product>
            return productObj;
        }

        /// <summary>
        /// GetSmallestOfTwo
        /// </summary>
        /// <param name="a">int</param>
        /// <param name="b">int</param>
        /// <returns>int</returns>
        public static int GetSmallestOfTwo(int a, int b)
        {
            return (a <= b) ? a : b;
        }
    }

    /// <summary>
    /// Product class
    /// </summary>
    class Product
    {
        public string ID { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public decimal Price { get; set; }
        public int StockAvailable { get; set; }
        public int WeeklySales { get; set; }

        public Product(string id, string name, string description, decimal price, int stockavailable)
        {
            ID = id;
            Name = name;
            Description = description;
            Price = price;
            StockAvailable = stockavailable;
        }

        public Product(string id, string name, string description, decimal price, int stockavailable, int weeklysales)
        {
            ID = id;
            Name = name;
            Description = description;
            Price = price;
            StockAvailable = stockavailable;
            WeeklySales = weeklysales;
        }

        public String ToString()
        {
            return "ID: " + ID + " Name: " + Name + " Description: " + Description +
                   " Price:" + Price + "StockAvailable: " + StockAvailable + " WeeklySales: " + WeeklySales;
        }
    }
}
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you so much @Blaatz0r. That is definitely on the right track. I am getting an error message: An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll Additional information: Index was out of range. Must be non-negative and less than the size of the collection. So that could be something to do with the structure/layout of the csv file. I'm not sure. Am I right in saying that from your code 'productContents' will become a new List<> with headings ProductID, Name, Description, Price, StockAvailable, WeeklySales.?
Where are you getting the exception?? what function and if possible what line??
I am getting the exception at this line: productContents.ElementAt(i).WeeklySales = Convert.ToInt32(salesDetails[i].Split(',')[1]);
I've edited the loop and added a small function that returns the smallest of the two indices. (it will make sure we won't have an OutOfRangeException. One thing tho the list sizes are probably not of equal length (products vs sales)
Thank you so much @Blaatz0r! That worked great, I just changed the output formatting a little. I ticked your answer but cannot give you an up-vote yet unfortunately as I need a reputation of 15 but your input is highly appreciated!
|
1

Let's suppose you have ProductID in each line of your salesdata.csv. It is not clear from the question - is it so or not. And by the way - it should have that ProductID, because I can't see how you can find product to update otherwise.

Ok, you've read a line from salesdata - noew you need to find correspondent product in your List. Here comes some problem, because List itself is not a very good data structure for it - you have to iterate over the whole list to find concrete product.

So it's better to change your List<Product> to Dictionary<string, Product> and populate it assuming dictionary key is Product.ID. In this case you will be able to find your product in O(1) time and update its WeeklySales like:

for (int i = 1; i < salesDetails.Length; i++)
{
    string currentLine = salesDetails[i];
    salesCol = currentLine.Split(',');

    string productID = salesCol[some_column_fromCSV];

    your_products_dictionary[productID].WeeklySales = Convert.ToInt(salesCol[1]);
}

Note it is pseudocode and here I don't bother about possible null-references and so on.

Also note - it may be not a good idea to read all content of csv file by File.ReadAllLines and then store it in array. because file can be very large and you can run out of memory. Instead you can open this file and read it line-by-line using, for example, TextReader Open and ReadLine methods.

1 Comment

Thank you very much for your detailed answer @Andy Korneyev I will look at using Dictionary<string, Product>. It might be a better approach.

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.