Benjamin Rogers
Benjamin Rogers

Reputation: 41

How to cleanup long if else statements that do almost the same thing

So I have this long stretch of c# code (forgive me im a beginner and its messy) but I basically want to repeat all the steps but also output the text to result to a file if "-o" & a filename (example.txt) are given in the command line arguments.

Currently, I have all the code copied from the first if statement in the else statement plus the additional code for outputting to file.

Is there a way to get around this / not have to repeat it but just refer to it and then add the extra steps?

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

            string inputFile = args[0];
            string inputPlane = args[1];
            string inputTime = args[2];

            // Check for output flag "-o"
            bool checkForOutput = Array.Exists(args, element => element == "-o");

            if (File.Exists(inputFile) && checkForOutput == true)
            {
                //================== Get inputFile formatted ==================
                List<string> lines = File.ReadAllLines(inputFile).ToList(); // Read text and put into list
                string words = lines.Aggregate((i, j) => i + " " + j).ToString(); // Split into sentences
                string[] splitWords = words.Split(); // Each individual word
                int listLength = lines.Count; // Count total lines
                string[] stations = new string[listLength];


                //================== Get plane file formatted ==================
                List<string> planeLines = File.ReadAllLines(inputPlane).ToList(); // Read text and put into list
                string planeElements = planeLines.Aggregate((i, j) => i + " " + j).ToString();
                string[] stringPlaneSpec = planeElements.Split();
                int[] intPlaneSpec = new int[stringPlaneSpec.Length];
                for (int n = 0; n < stringPlaneSpec.Length; n++)
                    intPlaneSpec[n] = int.Parse(stringPlaneSpec[n]);


                //================== Store station Details ==================
                Station[] stationDetails = new Station[listLength];
                int stationCounter = 0;
                while (stationCounter < listLength)
                {
                    for (int i = 0; i < splitWords.Length; i += 3)
                    {
                        stationDetails[stationCounter] = new Station(splitWords[i], Convert.ToInt32(splitWords[i + 1]), Convert.ToInt32(splitWords[i + 2]));
                        stationCounter++;
                    }
                }
                List<Station> stationNamesList = stationDetails.ToList();


                //================== Store station names ==================

                string[] names = new string[listLength];
                int nameCounter = 0;
                while (nameCounter < listLength)
                {
                    for (int i = 0; i < splitWords.Length; i += 3)
                    {
                        names[nameCounter] = (splitWords[i]);
                        nameCounter++;
                    }
                }
                //================== Store plane details ==================
                Plane plane1 = new Plane(intPlaneSpec[0], intPlaneSpec[1], intPlaneSpec[2], intPlaneSpec[3], intPlaneSpec[4]);

                //================== Store distance totals between position [i] & [i + 1] ==================

                double[] distanceTotal = new double[listLength];

                for (int i = 0; i < stationDetails.Length - 1; i++)
                {
                    distanceTotal[i] = Math.Round(Station.Distance((stationDetails[i].XValue),
                    (stationDetails[i + 1].XValue),
                    (stationDetails[i].YValue),
                    (stationDetails[i + 1].YValue)), 4);
                }
                int lastStation = stationDetails.GetUpperBound(0);

                // Store last distance total
                distanceTotal[lastStation] = Math.Round(Station.Distance((stationDetails[lastStation].XValue),
                (stationDetails[0].XValue),
                (stationDetails[lastStation].YValue),
                (stationDetails[0].YValue)), 4);

                //================== Setup list for storing times ==================

                DateTime startTime = DateTime.Parse(inputTime);
                List<DateTime> temporaryTimes = new List<DateTime>();
                temporaryTimes.Add(startTime); // Add initial value "23:00
                List<string> timeStrings = new List<string>();

                for (int i = 0; i < distanceTotal.Length; i++)
                {
                    temporaryTimes.Add(startTime.AddMinutes((Tour.CalTime(distanceTotal[i], plane1))));
                    string stringVersion = startTime.ToString(@"hh\:mm");
                    timeStrings.Add(stringVersion);
                    startTime = (startTime.AddMinutes((Tour.CalTime(distanceTotal[i], plane1))));
                }

                //================== Store total duration of trip ==================
                int last = (temporaryTimes.Count);
                TimeSpan totalTime = temporaryTimes[last - 1] - temporaryTimes[0];

                //================== Setup list for storing tour names ==================
                List<string> tourNames = new List<string>();

                //================== Output to Console Window & file ==================
                // Setup output file
                string outputFile = args[4];
                FileStream outFile = new FileStream(outputFile, FileMode.Create, FileAccess.Write);
                StreamWriter writer = new StreamWriter(outFile);

                Console.WriteLine("Reading input from {0}", inputFile);
                if (totalTime.Days >= 1)
                {
                    Console.WriteLine("Tour time: {0} days {1} hours {2} minutes", totalTime.Days, totalTime.Hours, totalTime.Minutes);

                }
                else
                {
                    Console.WriteLine("Tour time: {0} hours {1} minutes", totalTime.Hours, totalTime.Minutes);
                }

                Console.WriteLine("Optimising tour length: Level 1...");
                Console.WriteLine("Tour length: {0}", distanceTotal.Sum()); // sum of trip
                writer.WriteLine(distanceTotal.Sum()); // write sum to output file

                for (int i = 0; i < stationDetails.Length - 1; i++)
                {
                    Console.WriteLine("{0}\t->\t{1}\t{2}",
                    stationDetails[i].StationName.Substring(0, 2),
                    stationDetails[i + 1].StationName.Substring(0, 2),
                    distanceTotal[i]);

                    // Store names to tour names
                    tourNames.Add(stationDetails[i].StationName.Substring(0, 2));
                    tourNames.Add(stationDetails[i + 1].StationName.Substring(0, 2));

                    writer.WriteLine("{0}\t->\t{1}\t{2}",
                    stationDetails[i].StationName.Substring(0, 2),
                    stationDetails[i + 1].StationName.Substring(0, 2),
                    Math.Round(Station.Distance((stationDetails[i].XValue),
                    (stationDetails[i + 1].XValue),
                    (stationDetails[i].YValue),
                    (stationDetails[i + 1].YValue)), 4));

                }
                // Write Last distance to console
                Console.WriteLine("{0}\t->\t{1}\t{2}",
                stationDetails[lastStation].StationName.Substring(0, 2),
                stationDetails[0].StationName.Substring(0, 2), distanceTotal[lastStation]);

                //================== Store tour Details in object ==================
                Tour tour1 = new Tour(4.2, plane1, tourNames, temporaryTimes, totalTime);

                ////================== Algorithm ==================

                //// Empty tour with post office initially added
                List<Station> stationsLeft = stationDetails.ToList();
                List<Station> fuckingDone = Tour.SimpleHueristic(stationsLeft);

                foreach (Station var in fuckingDone)
                {
                    Console.WriteLine("{0} {1} {2}", var.StationName, var.XValue, var.YValue);
                }

                // Write last distance to output file
                writer.WriteLine("{0}\t->\t{1}\t{2}",
                stationDetails[lastStation].StationName.Substring(0, 2),
                stationDetails[0].StationName.Substring(0, 2),
                Math.Round(Station.Distance((stationDetails[lastStation].XValue),
                (stationDetails[0].XValue),
                (stationDetails[lastStation].YValue),
                (stationDetails[0].YValue)), 4));

                // Close output file
                writer.Close();
                outFile.Close();
            }


            //================== END OF IF STATEMENT - NEXT SECTION OF CODE (NEEDS TO BE THE SAME) ================

            else if (File.Exists(inputFile) && checkForOutput == false)
            {
                //================== Get inputFile formatted ==================
                List<string> lines = File.ReadAllLines(inputFile).ToList(); // Read text and put into list
                string words = lines.Aggregate((i, j) => i + " " + j).ToString(); // Split into sentences
                string[] splitWords = words.Split(); // Each individual word
                int listLength = lines.Count; // Count total lines
                string[] stations = new string[listLength];

                //================== Get plane file formatted ==================
                List<string> planeLines = File.ReadAllLines(inputPlane).ToList(); // Read text and put into list
                string planeElements = planeLines.Aggregate((i, j) => i + " " + j).ToString();
                string[] stringPlaneSpec = planeElements.Split();
                int[] intPlaneSpec = new int[stringPlaneSpec.Length];
                for (int n = 0; n < stringPlaneSpec.Length; n++)
                    intPlaneSpec[n] = int.Parse(stringPlaneSpec[n]);

                //================== Store station Details ==================

                Station[] stationDetails = new Station[listLength];
                int stationCounter = 0;
                while (stationCounter < listLength)
                {
                    for (int i = 0; i < splitWords.Length; i += 3)
                    {
                        stationDetails[stationCounter] = new Station(splitWords[i], Convert.ToInt32(splitWords[i + 1]), Convert.ToInt32(splitWords[i + 2]));
                        stationCounter++;
                    }
                }

                //================== Store plane details ==================
                Plane plane1 = new Plane(intPlaneSpec[0], intPlaneSpec[1], intPlaneSpec[2], intPlaneSpec[3], intPlaneSpec[4]);

                //================== Store time details ==================
                DateTime newTime = DateTime.Parse(inputTime);
                string formatedTime = newTime.ToString("HH:mm");

                //================== Store distance totals between position [i] & [i + 1] ==================
                double[] distanceTotal = new double[listLength];

                for (int i = 0; i < stationDetails.Length - 1; i++)
                {
                    distanceTotal[i] = Math.Round(Station.Distance((stationDetails[i].XValue),
                    (stationDetails[i + 1].XValue),
                    (stationDetails[i].YValue),
                    (stationDetails[i + 1].YValue)), 4);
                }

                int lastStation = stationDetails.GetUpperBound(0);

                // Store last distance total
                distanceTotal[lastStation] = Math.Round(Station.Distance((stationDetails[lastStation].XValue),
                (stationDetails[0].XValue),
                (stationDetails[lastStation].YValue),
                (stationDetails[0].YValue)), 4);

                //================== Setup list for storing times ==================
                List<DateTime> temporaryTimes = new List<DateTime>();

                //================== Setup list for storing tour names ==================
                List<string> tourNames = new List<string>();

                //================== Output to only Console ==================
                Console.WriteLine("Reading input from {0}", inputFile);
                Console.WriteLine("Optimising tour length: Level 1...");
                Console.WriteLine("Tour length: {0}", distanceTotal.Sum()); // sum of trip

                for (int i = 0; i < stationDetails.Length - 1; i++)
                {

                    Console.WriteLine("{0}\t->\t{1}\t{2}",
                    stationDetails[i].StationName.Substring(0, 2),
                    stationDetails[i + 1].StationName.Substring(0, 2),
                    distanceTotal[i]);
                }

                // Output last distance back to post office
                Console.WriteLine("{0}\t->\t{1}\t{2}",
                stationDetails[lastStation].StationName.Substring(0, 2),
                stationDetails[0].StationName.Substring(0, 2), distanceTotal[lastStation]);
            }
            else
            {
                //========== Display error message if input is incorrect ============

                Console.WriteLine("Invalid Input");
            }

            Console.ReadLine();
        }
    }
}

The else statement basically does the same thing just without writing the result to a file.

Upvotes: 0

Views: 177

Answers (1)

Migg
Migg

Reputation: 484

That's a lot of code.

Your code clearly shows that most steps are common as long as the file exists. You can re-structure your code as follows:

  1. Perform validation first
  2. Perform the common steps
  3. Perform specific steps based on the checkForOutput flag

I recommend breaking up your code into methods, with each method doing a specific thing. That way, you won't need to add bar comments to explain what you're trying to do granted your method name is self-describing.

I've done part of the work below for you by refactoring out into methods GetInputFileFormatted, GetSplitWords, GetPlaneFileFormatted, GetStationDetails. I leave the remaining exercise for you.

Another thing I usually advise my developers is to clearly perform validation on top. Notice that I start by checking the existence of the file and immediately short-circuiting execution if that fails. This removes one level of nesting and makes your intentions clear immediately that the file path provided must exist before doing any execution.

static void Main(string[] args)
        {
            string inputFile = args[0];
            string inputPlane = args[1];
            string inputTime = args[2];

            // Check for output flag "-o"
            bool checkForOutput = Array.Exists(args, element => element == "-o");

            if(!File.Exists(inputFile))
            {
                Console.WriteLine("Invalid Input");
                return;
            }

            var inputFileLines = GetInputFileFormatted(inputFile);
            var splitWords = GetSplitWords(inputFileLines);
            var planeFileLines = GetPlaneFileFormatted(inputPlane);
            var stationDetails = GetStationDetails(inputFileLines.Count, splitWords);

            if (checkForOutput == true)
            {
                //================== Store station names ==================

                string[] names = new string[listLength];
                int nameCounter = 0;
                while (nameCounter < listLength)
                {
                    for (int i = 0; i < splitWords.Length; i += 3)
                    {
                        names[nameCounter] = (splitWords[i]);
                        nameCounter++;
                    }
                }
                //================== Store plane details ==================
                Plane plane1 = new Plane(intPlaneSpec[0], intPlaneSpec[1], intPlaneSpec[2], intPlaneSpec[3], intPlaneSpec[4]);

                //================== Store distance totals between position [i] & [i + 1] ==================

                double[] distanceTotal = new double[listLength];

                for (int i = 0; i < stationDetails.Length - 1; i++)
                {
                    distanceTotal[i] = Math.Round(Station.Distance((stationDetails[i].XValue),
                    (stationDetails[i + 1].XValue),
                    (stationDetails[i].YValue),
                    (stationDetails[i + 1].YValue)), 4);
                }
                int lastStation = stationDetails.GetUpperBound(0);

                // Store last distance total
                distanceTotal[lastStation] = Math.Round(Station.Distance((stationDetails[lastStation].XValue),
                (stationDetails[0].XValue),
                (stationDetails[lastStation].YValue),
                (stationDetails[0].YValue)), 4);

                //================== Setup list for storing times ==================

                DateTime startTime = DateTime.Parse(inputTime);
                List<DateTime> temporaryTimes = new List<DateTime>();
                temporaryTimes.Add(startTime); // Add initial value "23:00
                List<string> timeStrings = new List<string>();

                for (int i = 0; i < distanceTotal.Length; i++)
                {
                    temporaryTimes.Add(startTime.AddMinutes((Tour.CalTime(distanceTotal[i], plane1))));
                    string stringVersion = startTime.ToString(@"hh\:mm");
                    timeStrings.Add(stringVersion);
                    startTime = (startTime.AddMinutes((Tour.CalTime(distanceTotal[i], plane1))));
                }

                //================== Store total duration of trip ==================
                int last = (temporaryTimes.Count);
                TimeSpan totalTime = temporaryTimes[last - 1] - temporaryTimes[0];

                //================== Setup list for storing tour names ==================
                List<string> tourNames = new List<string>();

                //================== Output to Console Window & file ==================
                // Setup output file
                string outputFile = args[4];
                FileStream outFile = new FileStream(outputFile, FileMode.Create, FileAccess.Write);
                StreamWriter writer = new StreamWriter(outFile);

                Console.WriteLine("Reading input from {0}", inputFile);
                if (totalTime.Days >= 1)
                {
                    Console.WriteLine("Tour time: {0} days {1} hours {2} minutes", totalTime.Days, totalTime.Hours, totalTime.Minutes);

                }
                else
                {
                    Console.WriteLine("Tour time: {0} hours {1} minutes", totalTime.Hours, totalTime.Minutes);
                }

                Console.WriteLine("Optimising tour length: Level 1...");
                Console.WriteLine("Tour length: {0}", distanceTotal.Sum()); // sum of trip
                writer.WriteLine(distanceTotal.Sum()); // write sum to output file

                for (int i = 0; i < stationDetails.Length - 1; i++)
                {
                    Console.WriteLine("{0}\t->\t{1}\t{2}",
                    stationDetails[i].StationName.Substring(0, 2),
                    stationDetails[i + 1].StationName.Substring(0, 2),
                    distanceTotal[i]);

                    // Store names to tour names
                    tourNames.Add(stationDetails[i].StationName.Substring(0, 2));
                    tourNames.Add(stationDetails[i + 1].StationName.Substring(0, 2));

                    writer.WriteLine("{0}\t->\t{1}\t{2}",
                    stationDetails[i].StationName.Substring(0, 2),
                    stationDetails[i + 1].StationName.Substring(0, 2),
                    Math.Round(Station.Distance((stationDetails[i].XValue),
                    (stationDetails[i + 1].XValue),
                    (stationDetails[i].YValue),
                    (stationDetails[i + 1].YValue)), 4));

                }
                // Write Last distance to console
                Console.WriteLine("{0}\t->\t{1}\t{2}",
                stationDetails[lastStation].StationName.Substring(0, 2),
                stationDetails[0].StationName.Substring(0, 2), distanceTotal[lastStation]);

                //================== Store tour Details in object ==================
                Tour tour1 = new Tour(4.2, plane1, tourNames, temporaryTimes, totalTime);

                ////================== Algorithm ==================

                //// Empty tour with post office initially added
                List<Station> stationsLeft = stationDetails.ToList();
                List<Station> fuckingDone = Tour.SimpleHueristic(stationsLeft);

                foreach (Station var in fuckingDone)
                {
                    Console.WriteLine("{0} {1} {2}", var.StationName, var.XValue, var.YValue);
                }

                // Write last distance to output file
                writer.WriteLine("{0}\t->\t{1}\t{2}",
                stationDetails[lastStation].StationName.Substring(0, 2),
                stationDetails[0].StationName.Substring(0, 2),
                Math.Round(Station.Distance((stationDetails[lastStation].XValue),
                (stationDetails[0].XValue),
                (stationDetails[lastStation].YValue),
                (stationDetails[0].YValue)), 4));

                // Close output file
                writer.Close();
                outFile.Close();
            }


            //================== END OF IF STATEMENT - NEXT SECTION OF CODE (NEEDS TO BE THE SAME) ================

            else if (checkForOutput == false)
            {
                //================== Store plane details ==================
                Plane plane1 = new Plane(intPlaneSpec[0], intPlaneSpec[1], intPlaneSpec[2], intPlaneSpec[3], intPlaneSpec[4]);

                //================== Store time details ==================
                DateTime newTime = DateTime.Parse(inputTime);
                string formatedTime = newTime.ToString("HH:mm");

                //================== Store distance totals between position [i] & [i + 1] ==================
                double[] distanceTotal = new double[listLength];

                for (int i = 0; i < stationDetails.Length - 1; i++)
                {
                    distanceTotal[i] = Math.Round(Station.Distance((stationDetails[i].XValue),
                    (stationDetails[i + 1].XValue),
                    (stationDetails[i].YValue),
                    (stationDetails[i + 1].YValue)), 4);
                }

                int lastStation = stationDetails.GetUpperBound(0);

                // Store last distance total
                distanceTotal[lastStation] = Math.Round(Station.Distance((stationDetails[lastStation].XValue),
                (stationDetails[0].XValue),
                (stationDetails[lastStation].YValue),
                (stationDetails[0].YValue)), 4);

                //================== Setup list for storing times ==================
                List<DateTime> temporaryTimes = new List<DateTime>();

                //================== Setup list for storing tour names ==================
                List<string> tourNames = new List<string>();

                //================== Output to only Console ==================
                Console.WriteLine("Reading input from {0}", inputFile);
                Console.WriteLine("Optimising tour length: Level 1...");
                Console.WriteLine("Tour length: {0}", distanceTotal.Sum()); // sum of trip

                for (int i = 0; i < stationDetails.Length - 1; i++)
                {

                    Console.WriteLine("{0}\t->\t{1}\t{2}",
                    stationDetails[i].StationName.Substring(0, 2),
                    stationDetails[i + 1].StationName.Substring(0, 2),
                    distanceTotal[i]);
                }

                // Output last distance back to post office
                Console.WriteLine("{0}\t->\t{1}\t{2}",
                stationDetails[lastStation].StationName.Substring(0, 2),
                stationDetails[0].StationName.Substring(0, 2), distanceTotal[lastStation]);
            }
            else
            {
                //========== Display error message if input is incorrect ============

                Console.WriteLine("Invalid Input");
            }

            Console.ReadLine();            
        }

        static List<string> GetInputFileFormatted(string inputFile)
        {
            List<string> lines = File.ReadAllLines(inputFile).ToList(); // Read text and put into list
            return lines;
        }

        static string[] GetSplitWords(List<string> inputFileLines)
        {
            string words = inputFileLines.Aggregate((i, j) => i + " " + j).ToString(); // Split into sentences
            return words.Split(); // Each individual word
        }

        static List<string> GetPlaneFileFormatted(string inputPlane)
        {
            List<string> planeLines = File.ReadAllLines(inputPlane).ToList(); // Read text and put into list
            string planeElements = planeLines.Aggregate((i, j) => i + " " + j).ToString();
            string[] stringPlaneSpec = planeElements.Split();
            int[] intPlaneSpec = new int[stringPlaneSpec.Length];
            for (int n = 0; n < stringPlaneSpec.Length; n++)
                intPlaneSpec[n] = int.Parse(stringPlaneSpec[n]);
            return planeLines;
        }

        static Station[] GetStationDetails(int inputFileLinesLength, string[] splitWords)
        {
            Station[] stationDetails = new Station[inputFileLinesLength];
            int stationCounter = 0;
            while (stationCounter < inputFileLinesLength)
            {
                for (int i = 0; i < splitWords.Length; i += 3)
                {
                    stationDetails[stationCounter] = new Station(splitWords[i], Convert.ToInt32(splitWords[i + 1]), Convert.ToInt32(splitWords[i + 2]));
                    stationCounter++;
                }
            }
            return stationDetails;
        }

Upvotes: 1

Related Questions