-1

I was working on a small program that basically reads from a txt multiple arrays and writes them to another file, but, additionally, it should generate a unique number and place it just before the information. I got the first part working with no problems but the second part is causing me problems even though it should work.

    public static void Main(string[] args)
    {

        StreamReader vehiclereader = new StreamReader(@"C:\Users\Admin\Desktop\Program\vehicles.txt");
        string line = vehiclereader.ReadToEnd();

        string ID;
        string category;

        string Type;
        string Brand;
        string Model;
        string Year;
        string Colour;

        while (line != null)
        {
            var parts = line.Split(',');
            Type = parts[0];
            Brand = parts[1];
            Model = parts[2];
            Year = parts[3];
            Colour = parts[4];

            Console.WriteLine(line);

            string[] lines = { line };
            System.IO.File.WriteAllLines(@"C:\Users\Admin\Desktop\Program\vehicles2.txt", lines);

            List<string> categories = new List<string>();


            categories.Add(Type);
            int count = categories.Where(x => x.Equals(Type)).Count(); 
            ID = Type.Substring(0, 4) + count.ToString("00");

            Console.ReadKey();
        }
    }
}

Currently, this code reads from a txt file, displays it into the console and writes it back to another txt file. This is fine, the part that is not willing to work is the unique number generator.

Last 5 lines of code are supposed to add a unique number just before 'Type' data and would always start from 001. If the 'Type' data is identical, then the number just grows in ascending order. Otherwise, the unique number should reset for new types and start counting from 001 and should keep growing for identical types. (e.g. For all lightweight vehicles the counter should be the same and for heavyweight vehicles the counter should be different but count all of the heavy vehicles)

I'm open to any help or suggestions!

sevd
  • 7
  • 5
  • Your categories list will only ever have one item in it because you declare a new list in each loop iteration. The count of items equal to Type will always be one. Furthermore you're not doing anything with the ID variable. – pinkfloydx33 Feb 24 '18 at 23:48
  • Have you actually run this code on a file with more than 1 line of text? – Mark Benningfield Feb 24 '18 at 23:52
  • https://stackoverflow.com/questions/2920696/how-generate-unique-integers-based-on-guids – Broom Feb 25 '18 at 00:06
  • @pinkfloydx33 How do I stop list from occurring in every loop iteration? Do I have to use a different loop? What about Type always being one, how to prevent that? – sevd Feb 25 '18 at 00:16
  • @MarkBenningfield I cannot do that right now since it shows me 'Use of unassigned local variable 'category'. However, if I comment out those 4 lines then it displays all of the necessary information which is about 15 lines. – sevd Feb 25 '18 at 00:19
  • @Broom I may be wrong, but, to me, it seems like a random number generator.I need a number generator that generates a number from 001 to let's say 100, for each individual type of data. – sevd Feb 25 '18 at 00:21
  • It's not random, it's unique. Almost guaranteed. But if you only want a running count of whatever you're looping over, just declare an int before the loop and increment it on the first line inside the loop – Broom Feb 25 '18 at 00:25
  • This `string line = vehiclereader.ReadToEnd(); ` reads _all the lines in the file_ into the `line` variable. This code has a lot more problems than generating an incrementing type id value. – Mark Benningfield Feb 25 '18 at 00:29

1 Answers1

0

There are a variety of issues and suggestions with this code, allow me to list them before providing a corrected version:

  1. StreamReader is disposable, so put it in a "using" block.
  2. ReadToEnd reads the entire file into a single string, whereas your code structure is expecting it to return a line at a time, so you want the "ReadLine" method.
  3. The value of line does not get modified within your loop, so you will get an infinite loop (program that never ends).
  4. (Suggestion) Use lower case letters at the start of your variable names, it will help you spot what things are variables and what are classes/methods.
  5. (Suggestion) The local variables are declared in a wider scope than they are needed. There is no performance hit to only declaring them within the loop, and it makes your program easier to read.
  6. "string[] lines = { line };" The naming implies that you think this will split the single line into an array of lines. But actually, it will just create an array with one item in it (which we've already established is the entire contents of the file).
  7. "category" is an unused variable; but actually, you don't use Brand, Model, Year or Colour either.
  8. It would have helped if the question had a couple of lines as an example of input and output.
  9. Since, you're processing a line at a time, we might as well write the output file a line at a time, rather than hold the entire file in memory at once.
  10. The ID is unused, and that code is after the line writing the output file, so there is no way it will appear in there.
  11. "int count = categories.Where(x => x.Equals(type)).Count();" is inefficient, as it iterates through the list twice: prefer "int count = categories.Count(x => x.Equals(type));"
  12. Removed the "Console.Write", since the output goes to a file.
  13. Is that "Console.ReadKey" meant to be within the loop, or after it? I put it outside.

I created a class to be responsible for the counting, to demonstrate how it is possible to "separate concerns".

Clearly I don't have your files, so I don't know whether this will work.

class Program
{
    public static void Main(string[] args)
    {
        var typeCounter = new TypeCounter();

        using (StreamWriter vehicleWriter = new StreamWriter(@"C:\Users\Admin\Desktop\Program\vehicles2.txt"))
        using (StreamReader vehicleReader = new StreamReader(@"C:\Users\Admin\Desktop\Program\vehicles.txt"))
        {
            string line;
            while ((line = vehicleReader.ReadLine()) != null)
            {
                var parts = line.Split(',');
                string type = parts[0].Substring(0, 4); // not sure why you're using substring, I'm just matching what you did
                var identifier = typeCounter.GetIdentifier(type);
                vehicleWriter.WriteLine($"{identifier},{line}");
            }
        }

        Console.ReadKey();
    }
}

public class TypeCounter
{
    private IDictionary<string, int> _typeCount = new Dictionary<string, int>();

    public string GetIdentifier(string type)
    {
        int number;
        if (_typeCount.ContainsKey(type))
        {
            number = ++_typeCount[type];
        }
        else
        {
            number = 1;
            _typeCount.Add(type, number);
        }

        return $"{type}{number:00}"; // feel free to use more zeros
    }
}
Richardissimo
  • 5,596
  • 2
  • 18
  • 36
  • I appreciate what you have done, did not expect anyone to craft such complicated program for such small concern. I truly appreciate this, it has solved everything. Also, thank you for pointing out everything that is wrong with the code! – sevd Feb 26 '18 at 18:23