RA19
RA19

Reputation: 819

Summary of outputs from for loop so it outputs a summary

Trying to get a summary from my current output. E.g. Hello: 5, World: 8, HelloWorld: 20, integer: 5. Currently this accepts a user input e.g. 1,10, 1 being minimum and 10 being maximum and outputs the following from the for loop. Don't know how to get the output into an array and then aggregate this.

Code so far:

 Console.WriteLine("Please enter a range?");
        string range = Console.ReadLine();
        string first = range.Split(',')[0];
        string last = range.Split(',')[1];
        int min = Int32.Parse(first);
        int max = Int32.Parse(last);
        Console.WriteLine("");
        Console.WriteLine("Heres the Output");
        Console.WriteLine("");

        for (int i = min; i < max ; i++ )
        {
            bool hello = i % 3 == 0;
            bool world = i % 5 == 0;

            if (hello && world)
                Console.WriteLine("HelloWorld");

            else if (hello)
                Console.WriteLine("Hello");
            else if (world)
                Console.WriteLine("World");
            else
                Console.WriteLine(i);
        }

        string list = Console.ReadLine();
        Console.WriteLine(list);

Upvotes: 1

Views: 183

Answers (1)

Dmitrii Bychenko
Dmitrii Bychenko

Reputation: 186813

All you have to do is to use modular arithmetics; providing that 0 <= min < max :

private static int CountDivs(int value, int divisor) {
  return value < 0 ? 0 : value / divisor + 1;
}

private static string Solution(int min, int max) {
  int hello = CountDivs(max - 1, 3) - CountDivs(min - 1, 3);
  int world = CountDivs(max - 1, 5) - CountDivs(min - 1, 5);
  int helloWorld = CountDivs(max - 1, 3 * 5) - CountDivs(min - 1, 3 * 5);
  // others: Inclusion–exclusion principle  
  int other = max - min - hello - world + helloWorld;

  return $"hello: {hello} world: {world} integer: {other}"; 
}

// Test (your example)
Console.WriteLine(Solution(1, 10));
// My comment [8..14) i.e. 8, 9, 10, 11, 12, 13
Console.WriteLine(Solution(8, 14));

Outcome:

hello: 3 world: 1 integer: 5
hello: 2 world: 1 integer: 3

Please, notice, that the solution has O(1) time complexity (loop will be inefficient, on inputs like Solution(100, 1000000000))

Edit: if you want to change your current code a bit and have an aggregate solution, you can try to extract the loop into a method and use Linq to aggregate the items:

using System.Linq;

...

private static IEnumerable<string> Generator(int min, int max) {
  // Your loop extracted: put "yield return ..." instead of "Console.WriteLine(...)"
  for (int i = min; i < max; ++i) {
    bool hello = i % 3 == 0;
    bool world = i % 5 == 0;

    if (hello && world) {
      // Or if you want return twice, just do it twice:
      // yield return "Hello";
      // yield return "World";

      yield return "HelloWorld";
    } 
    else if (hello)
      yield return "Hello";
    else if (world)
      yield return "World";
    else
      yield return "integer";
  }
}

...

var data = Generator(1, 10)
  .GroupBy(item => item)
  .OrderBy(chunk => chunk.Key)
  .Select(chunk => $"{chunk.Key}: {chunk.Count()}");

var result = string.Join(" ", data);

Console.WriteLine(result);

Outcome:

Hello: 3 integer: 5 World: 1

Edit 2: No Linq solution, manual grouping

int min = 1;
int max = 10;

Dictionary<string, int> counts = new Dictionary<string, int>() {
  { "HelloWorld", 0},
  { "Hello", 0},
  { "World", 0},
  { "integer", 0},
};

foreach (var item in Generator(1, 10))
  counts[item] += 1;

string result = 
  $"Hello: {counts["Hello"]} World: {counts["World"]} integer: {counts["integer"]}";

Console.Write(result);

Outcome:

Hello: 3 World: 1 integer: 5

Upvotes: 1

Related Questions