2

So I have this very simple program that I have created that gets the user input and then pass the values to the method named average. Everything is perfectly fine, however, something crossed my mind like "What if the user only enters two numbers or an array of numbers?". I know that I have to use array as a parameter, but somehow I am not sure how to accomplish what i want to do. Do you guys have any tips on how I can achieve what i am trying to do? My code is here:

using System;

namespace Averages
{
class Program
{
    static void Main(string[] args)
    {                    
        Console.WriteLine("Enter number(s): ");
        double num1 = Convert.ToInt32(Console.ReadLine());
        double num2 = Convert.ToInt32(Console.ReadLine());
        double num3 = Convert.ToInt32(Console.ReadLine());
        average(num1, num2, num3);         
        Console.ReadKey();           
    }
    static void average(double num1, double num2, double num3)
    {
        double avg = (num1 + num2 + num3) / 3;
        Console.WriteLine("You have entered: " + num1 + ", " + num2 + ", " + num3);
        Console.WriteLine("The average is: " + avg);                                 
    }
 }
}

I would appreciate any help. Thank you!

Mihir Dave
  • 3,954
  • 1
  • 12
  • 28
Cyrus
  • 47
  • 6
  • 3
    At a high level: (1) Create a single `List nums` variable, (2) Put the call to `Console.ReadLine()` in a loop so the user can add to it as many times as they like (don't forget to include a way for the user to stop entering values and exit the loop, for example exit on any non-numeric value), (3) Pass the `List` to your `average()` method instead of three `doubles`. – David Jul 20 '18 at 13:56
  • 1
    Your method should expect an array/list, something like `average(double[] myArray) {... }`. – MakePeaceGreatAgain Jul 20 '18 at 14:04
  • Hey all! Thank you so much for the help! I have tried every suggestion you guys gave me and with a couple fixes, the app is running just like I wanted it to be. The one that I like the most is the one from Nino because the code is laid out in a way that it is easier to understand for an intermediate programmer like me. Again, Thank you everyone! – Cyrus Jul 20 '18 at 15:02
  • 1
    Glad i could help. Marking answer as a solution is a way to say thanks – Nino Jul 20 '18 at 15:02

8 Answers8

3

you can ask user for input of comma delimited numbers. Or, you can repeat input until user enters something like 0. I that case, you can change your program into this:

using System;
using System.Collections.Generic;
using System.Linq;

namespace Averages
{
    class Program
    {
        static void Main(string[] args)
        {
            //list to hold your numbers, way more flexible than array
            List<double> enteredNubers = new List<double>();

            //message user
            Console.WriteLine("Enter number(s) or 0 to end: ");

            //run this block of code indefinitely
            while (true)
            {
                //take user input
                string userinput = Console.ReadLine().Trim();
                //if user enters 0, exit this loop
                if (userinput == "0")
                    break;


                double num;
                //try to convert text to number
                if (double.TryParse(userinput, out num))
                {
                    //if it is successful, add number to list
                    enteredNubers.Add(num);
                }
                else //else message user with error
                    Console.WriteLine("Wrong input. Please enter number or 0 to end");
            }

            //when loop is exited (when user entered 0), call method that calculates average
            Average(enteredNubers);
            Console.ReadKey();
        }
        static void Average(List<double> numbers)
        {
            double sum = 0;
            //go through list and add each number to sum
            foreach (double num in numbers)
            {
                sum += num;
            }
            //or, you can sum it using linq like this:
            //sum = numbers.Sum();
            //or you can even calculate average by calling Average method on list, like numbers. Average();

            //show message  - all the entered numbers, separated by comma
            Console.WriteLine("You have entered: " + string.Join(", ", numbers.ToArray()));
            //write average
            Console.WriteLine("The average is: " + sum/numbers.Count);
        }
    }
}
Nino
  • 6,931
  • 2
  • 27
  • 42
2

Here Update your methods Accordingly

static void Main(string[] args)
{                    
    Console.WriteLine("Type Exit to stop the program... \nEnter number");
    List<double> doubleList = new List<double>();
    string input = Console.ReadLine();
    double d;
    while(!input.Equals("Exit"))
    {
        if(String.IsNullOrEmpty(input) || !Double.TryParse(input,out d))
        {
            break;
        }
        doubleList.Add(d);
        input = Console.ReadLine();
    }
    average(doubleList);         
    Console.ReadKey();           
}
static void average(List<double> doubleData)
{
    double total = 0;
    foreach (double number in doubleData)
    {
        total += number;
    }
    Console.WriteLine("Average = " + total/doubleData.Count);                                
}
Mihir Dave
  • 3,954
  • 1
  • 12
  • 28
2

Let's solve the problem step by step. First we want to add a single double:

  private static bool ReadDouble(out double value) {
    value = 0.0;

    while (true) {
      Console.WriteLine("Enter number or X to exit:");

      string input = Console.ReadLine().Trim();

      if (input == "X" || input == "x") 
        return false;
      else if (double.TryParse(input, out value)) 
        return true;

      Console.Write("Syntax error, please, try again.");
    }
  }

Now we are ready to read arbitrary number of values. Since we don't know the number, List<double> is a better choice than double[]

  using System.Collections.Generic;

  ...

  private static List<double> ReadDoubles() {
    List<double> result = new List<double>();

    while (ReadDouble(out var value))
      result.Add(value);

    return result;        
  }

Finally, we want to compute average

  static void Main(string[] args) {
    List<double> list = ReadDoubles();

    if (list.Count <= 0)
      Console.WriteLine("Empty list: no average");
    else {
      double sum = 0.0;

      foreach (double item in list)
        sum += item;

      double avg = sum / list.Count;

      Console.Write("The average is: " + avg);
    }
  }

However, you can do it in just few lines via Linq:

  using System.Collections.Generic;
  using System.Collections.Linq;

  ...

  static void Main(string[] args) {
    Console.WriteLine("Enter numbers separated by spaces, e.g. 1 2 3 15");

    double avg = Console
      .ReadLine()
      .Split(new char[] { ' '}, StringSplitOptions.RemoveEmptyEntries)
      .Select(item => double.Parse(item))  
      .Average();

    Console.Write($"The average is: {avg}"); 
  } 
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
1

Something like the following should meet your needs:

string stopLine = "STOP";
List<double> lines = new List<double>();
string line;
while ((line = Console.ReadLine()) != stopLine) {
    lines.Add(Convert.ToDouble(line));
}
Average(lines);
Console.ReadLine();

Now your average method becomes

private static void Average(List<double> lines) {
    Console.WriteLine(lines.Average());
}

Note that you should handle the case where the input is not a number.

ivcubr
  • 1,988
  • 9
  • 20
  • 28
1
static void Main(string[] args)
{
    Console.WriteLine("Enter number(s): ");
    string input = "";
    List<double> doubleList = new List<double>();
    while (input != "q")
    {
        input = Console.ReadLine();
        if(input != "q")
        {
            try
            {
                doubleList.Add(Convert.ToInt32(input));
            }
            catch
            {
                Console.WriteLine("Invalid input");
            }
        }
    }

    average(doubleList);
    Console.ReadKey();
}
static void average(List<double> myList)
{
    double sum = 0;
    Console.Write("You have entered: ")
    foreach (int element in myList)
    {
        sum += element;
        Console.Write(element + ", ");
    }
    Console.WriteLine("");

    double avg = sum / myList.Count;

    Console.WriteLine("The average is: " + avg);
}
misanthrop
  • 771
  • 7
  • 32
1

You have a couple options. Either ask for the user input to be delimited somehow. For example a comma delimited user input would be"1, 2, 3, 4". You've then got to worry about parsing that and ensuring the user entered valid input.

Another option is to have a while loop that has Console.ReadLine() within, and you only exit the loop when the user enters a pre-determined exit word (such as "stop" or exit")

    static void Main(string[] args)
    {
        var inputValues = new List<double>();

        while (true)
        {
            var input = Console.ReadLine();

            if (input.Equals("stop", StringComparison.InvariantCultureIgnoreCase))
                break;

            if (double.TryParse(input, out double inputValue))
            {
                inputValues.Add(inputValue);
            }
            else
            {
                Console.WriteLine("Invalid input!");
            }
        }


        PrintAverage(inputValues);
        Console.ReadKey();
    }

    static void PrintAverage(IEnumerable<double> values)
    {
        Console.WriteLine("You have entered: {0}", string.Join(", ", values));
        Console.WriteLine("The average is: {0}", values.Average());
    }

Here I've opted for the second option. It'll continuously loop until the input is stop. It will also now try parse the value rather than directly convert, and will print a warning message if the parse failed.

If the parse was successful it's added to our inputValues collection. Once out of the while loop, we pass the collection to PrintAverage - a method that takes an IEnumerable<double> (could be one value, 100 values, or no values). Because List implements IEnumerable, we can pass our list to this method. IEnumerable has an Average() method built-in.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
p3tch
  • 1,414
  • 13
  • 29
1
static void Main(string[] args)
{
    var numbers = new List<double>();
    Console.WriteLine("Enter the three numbers, one per line");
    for (var i = 0; i < 3; ++i)
    {
        while (true)
        {
            if (double.TryParse(Console.ReadLine(), out var enteredNumber))
            {
                //the number is a number, so...
                numbers.Add(enteredNumber);
                break;
            }
            //if not a number...
            Console.WriteLine("That's not a number, try again");
        }
    }

    Average(numbers);
    Console.ReadKey();
}
static void Average(IEnumerable<double> numbers)
{
    var average = numbers.Average();
    Console.Write("You have entered: ");
    foreach (var num in numbers)
    {
        Console.Write($" {num}  ");
    }
    Console.WriteLine(String.Empty);
    Console.WriteLine("The average is: " + average);
}

In general, Lists are better than Arrays for this kind of thing; List's are stretchy, Arrays are not. If you want this to work with 4 (or 200) numbers, all you have to do is change the for loop's bounds.

I'm using double.TryParse, this way I can let the user correct a badly entered number (always assume users will enter bad data). I'm passing the collection of numbers to the average function as an IEnumerable and not a List (the Average function is hardly needed (note that the calculation of the average is just an extension method on collections of numerics) but you had one, so I included it. An IEnumerable cannot be changed by the called function, so it's more appropriate here (and, all lists (and all arrays, for that matter) are enumerable).

Flydog57
  • 6,851
  • 2
  • 17
  • 18
1

Looking at all these fancy answers,i guess people are forgetting the basics of programming.

The OP literally states using arrays and instead of that you all are pushing him into hard to read code. The guy is trying to learn the basics which obviously no one cares to learn about.

Dear Cyrus don't get into generics right away. I would suggest that you stick to arrays for a while.

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Enter number(s): ");
        double[] values = new double[3]; //initialize double array with its size

        for (int i = 0; i < values.Length; i++)
        {
            //iterate through the array and assign value to each index of it.
            values[i]=Convert.ToDouble(Console.ReadLine());
        }
        average(values);
        Console.ReadKey();
    }
    //set method that accepts double array as parameter
    static void average(double[] values)
    {
        double average =0;// declare var that will hold the sum of numbers 
        int length = values.Length;//get array length, use it to divide the summation of numbers
        Console.WriteLine("You have entered: ");
        for (int i = 0; i < values.Length; i++)
        {
            //also display the numbers if you need to
            Console.WriteLine(values[i]);
            //iterate through each value in the array and sum it up.
            average = values[i] + average;
        }
        //divide the sum of numbers by the length of array
        Console.WriteLine("The average is: " + (average/length));
    }

}

You can also dynamically set the length of the array by letting the user input its length, just play with code and let your imagination loose. Happy coding!

IteratioN7T
  • 363
  • 8
  • 21