1

I'm writing a program that takes user data values 1-10 and stores it into an array. I'm trying to figure out how to add a counter that will allow me to output how many times each number was typed and how many invalid numbers were typed.

    class Program
{
    static void Main(string[] args)
    {
        int[] data = GetData();
    }

    private static int[] GetData()
    {
        int[] dataArray = new int[100];
        int n = 0;
        int intValue = 0;

        while (true)
        {
            Console.WriteLine("Enter a number 0-10 (Q to end)");
            string lineValue = Console.ReadLine();

            if (lineValue.ToLower().Trim().Equals("q"))
            {
                break;
            }

            if (!int.TryParse(lineValue, out intValue))
            {
                Console.WriteLine("INVALID DATA - Try again.");
                continue;
            }

            if (intValue < 0 || intValue > 10)
            {
                Console.WriteLine("NUMERIC DATA OUT OF RANGE - Try again.");
                continue;
            }

            dataArray[++n] = intValue;
            dataArray[0] = n;
        }
        return dataArray;
    }
}
1
  • I'm guessing the downvotes are because you have to look pretty hard for the actual question. If you edit the question to make it clearer what exactly you're having problems with, hopefully they'll either take back the downvotes (or perhaps even upvote). Commented Sep 24, 2015 at 17:14

3 Answers 3

2

You could setup a counter before the while condition for the invalid numbers.

int invalidNumbersCounter = 0;

Then you could increment this counter each time the input is invalid:

if (!int.TryParse(lineValue, out intValue))
{
    Console.WriteLine("INVALID DATA - Try again.");
    invalidNumbersCounter++;  
    continue;
}

Regarding your other question, how many times each number, you could just use plain LINQ to do the trick.

static void Main(string[] args)
{
    int[] data = GetData();

    var statistics = data.GroupBy(x=>x)
                         .Select(gr => new 
                         { 
                             Number = gr.key, 
                             Times = gr.Count() 
                         });

    foreach(var statistic in statistics)
    {
        Console.WriteLine(String.Format("The number {0} found {1} times in you array", statistic.Number, statistic.Times));
    }
}

The result of the above query would be a sequence of objects of an anonymous type with two properties, the number and the number that this number is in the array.

Update

In order we avoid count the values that haven't been entered by the user and essentially are the initial values of the array, we could initialized the values of the array to -1, when we create the array, like below:

int[] dataArray = Enumerable.Repeat(-1, 100).ToArray();

Then we have to update our linq query to the following one:

 var statistics = data.Skip(1)
                      .Where(number => number!=-1)
                      .GroupBy(x=>x)
                      .Select(gr => new 
                      { 
                          Number = gr.key, 
                          Times = gr.Count() 
                      });
Sign up to request clarification or add additional context in comments.

8 Comments

There is a problem with the empty slots that will be counted as well(I would add a Where before the GroupBy to remove them). But this is what I was thinking of. (And also the value at data[0] should be excluded by the counting)
Hi Steve and thanks for your comment. I have one question. Since data, would be an array of integers, where would be the empty slots? There is definitely something that I didn't catch correctly.
@Christos i'm guessing because he initialized his int array as 100. If you only enter 2 numbers in the while, then there will be 98 individual 0s in the array right?
@Kritner I get your reasoning, but if someone enters 0, this would be a valid input, unless If I am didn't understood it correctly.
@Christos dotnetfiddle.net/vCH1r6 here's what i mean. If you run the app and enter "1" then "q" it will list 1 as listed once, and 0 as listed 99 times - even though the user never entered 0 a single time.
|
1

You could do this:

public class Program
{
    public static void Main(string[] args)
    {
        // note updated to use a list rather than array (just preference)
        List<int> data = GetData();         
    }

    private static List<int> GetData()
    {
        List<int> list = new List<int>();
        int intValue = 0;
        int invalidAttempts = 0; // added to keep track of invalid values

        while (true)
        {
            Console.WriteLine("Enter a number 0-10 (Q to end)");
            string lineValue = Console.ReadLine();

            if (lineValue.ToLower().Trim().Equals("q"))
            {
                break;
            }

            if (!int.TryParse(lineValue, out intValue))
            {
                Console.WriteLine("INVALID DATA - Try again.");
                invalidAttempts++;
                continue;
            }

            if (intValue < 0 || intValue > 10)
            {
                Console.WriteLine("NUMERIC DATA OUT OF RANGE - Try again.");
                invalidAttempts++;
                continue;
            }

            list.Add(intValue);
        }

        Console.WriteLine("Invalid attempts {0}", invalidAttempts);

        // this is using linq to group by the individual numbers (keys),
        // then creates an anon object for each key value and the number of times it occurs.
        // Create new anon object numbersAndCounts
        var numbersAndCounts = list
            // groups by the individual numbers in the list
            .GroupBy(gb => gb)
            // selects into a new anon object consisting of a "Number" and "Count" property
            .Select(s => new {
                Number = s.Key,
                Count = s.Count()
            });

        foreach (var item in numbersAndCounts)
        {
            Console.WriteLine("{0} occurred {1} times", item.Number, item.Count);
        }

        return list;
    }
}

note I'm using a list rather than array, i find them easier to work with.

Working demo:

https://dotnetfiddle.net/KFz1UY

Is it possible to make the output go in numeric order? Right now it just displays whatever numbers were typed first. Such as 1, 7, 7, 4 would be 1:1 7:2 4:1, how can I change this to go 1:1 4:1 7:2?

Sure is possible! See below (and updated original demo)

I just changed:

    var numbersAndCounts = list
        .GroupBy(gb => gb)
        .Select(s => new {
            Number = s.Key,
            Count = s.Count()
        });

to:

    var numbersAndCounts = list
        .GroupBy(gb => gb)
        .Select(s => new {
            Number = s.Key,
            Count = s.Count()
        })
        .OrderBy(ob => ob.Number);

4 Comments

Thanks. This works exactly how I wanted it to, however I'm not too familiar with the linq technique that you used.
LINQ is amazing if you're unfamiliar. Here's a getting started: msdn.microsoft.com/en-us/library/bb397933.aspx
Is it possible to make the output go in numeric order? Right now it just displays whatever numbers were typed first. Such as 1, 7, 7, 4 would be 1:1 7:2 4:1, how can I change this to go 1:1 4:1 7:2?
Ofcoure, you can do so. You just need an OrderBy(gb=>gb.Key) clause. Please put this clause just after the GroupBy and right before the projection, Select.
1

You already have an example of a counter (n) that you can use as an example to record the number of invalid inputs. Simply increment it inside this if block:

if (intValue < 0 || intValue > 10)
        {
            Console.WriteLine("NUMERIC DATA OUT OF RANGE - Try again.");
            myInvalidCounter ++;
            continue;
        }

To get a count of each number entered - you can analyse the data stored inside your dataArray.

EDIT: I just noticed you have two examples of invalid data - bad raw data and out of range data - you need to set the counters as appropriate - maybe one each or a shared one etc.

Comments

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.