DEV Community

mohamed Tayel
mohamed Tayel

Posted on

Article 1: Creating a Grid Formatter for Clean Data Display

Introduction

Displaying data in a clean and readable format is a fundamental task in software development. Whether you’re building a console application or exporting data to a file, organizing the data into a grid structure is often a necessity.

In this article, you’ll learn how to:

  1. Encapsulate data formatting logic in a reusable class.
  2. Dynamically calculate the number of columns based on the available width.
  3. Display data in a neatly formatted grid.

We’ll build a GridFormatter class from scratch and see it in action with step-by-step explanations.


Key Concepts

  1. Encapsulation:

    • The grid formatting logic will be wrapped inside the GridFormatter class, ensuring reusability and separation of concerns.
  2. Dynamic Column Calculation:

    • The number of columns will adjust dynamically based on the total width and the width of the data items.
  3. Flexibility:

    • The GridFormatter will work with any data type, making it generic and versatile.

Step-by-Step Implementation

Step 1: Define the GridFormatter Class

The GridFormatter class will:

  • Accept a collection of data items.
  • Format them into rows and columns based on the available width and the gap between columns.

Here’s the implementation:

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

namespace Utilities
{
    public class GridFormatter<T>
    {
        private readonly IList<T> _data;

        public GridFormatter(IEnumerable<T> inputData)
        {
            // Cache the input data in a list
            _data = inputData.ToList();
        }

        public IEnumerable<string> FormatGrid(int totalWidth, int gapWidth)
        {
            // Calculate the number of columns
            int columns = GetColumnCount(totalWidth, gapWidth);
            string gap = new string(' ', gapWidth);

            // Generate rows by taking the required number of items per row
            for (int i = 0; i < _data.Count; i += columns)
            {
                var row = _data.Skip(i).Take(columns)
                               .Select(item => item.ToString().PadRight(GetMaxItemWidth()));
                yield return string.Join(gap, row);
            }
        }

        private int GetColumnCount(int totalWidth, int gapWidth)
        {
            int maxItemWidth = GetMaxItemWidth();
            int columnWidth = maxItemWidth + gapWidth;
            return Math.Max(1, totalWidth / columnWidth);
        }

        private int GetMaxItemWidth()
        {
            return _data.Max(item => item.ToString()?.Length ?? 0);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Use the GridFormatter Class in a Program

Now let’s see how to use the GridFormatter class in a real application.

using System;
using System.Collections.Generic;
using Utilities;

class Program
{
    static void Main(string[] args)
    {
        // Step 1: Input data
        var data = new List<string> { "Alice", "Bob", "Charlie", "Diana", "Eve" };

        // Step 2: Create an instance of GridFormatter
        var formatter = new GridFormatter<string>(data);

        // Step 3: Format the grid with a total width of 30 and a gap width of 3
        var grid = formatter.FormatGrid(30, 3);

        // Step 4: Display the formatted grid
        Console.WriteLine("Formatted Grid:");
        foreach (var row in grid)
        {
            Console.WriteLine(row);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Run the Program

Input:

Data: Alice, Bob, Charlie, Diana, Eve
Total Width: 30
Gap Width: 3
Enter fullscreen mode Exit fullscreen mode

Output:

Formatted Grid:
Alice   Bob     Charlie
Diana   Eve
Enter fullscreen mode Exit fullscreen mode

How It Works

  1. Dynamic Column Calculation:

    • The GetColumnCount method calculates how many columns can fit within the given width. It takes into account the width of each item and the gap between columns.
  2. Row Generation:

    • Data is split into rows, each containing the appropriate number of items.
  3. Padding and Spacing:

    • Each item is padded to ensure consistent column alignment.

Takeaways

  1. Encapsulation:

    • The GridFormatter encapsulates all logic related to grid formatting, making it reusable across projects.
  2. Flexibility:

    • By using generics, the GridFormatter can work with any type of data.
  3. Dynamic Design:

    • The formatter adapts to the available width, making it highly versatile for different use cases.

Next Steps

In the next article, we’ll build a Shuffler class to randomize data efficiently using the Fisher-Yates Shuffle. This will complement the GridFormatter and allow us to create more dynamic applications, like randomized team assignments.

Stay tuned for Article 2: Building a Reusable Shuffler for Randomizing Data! 🚀

Top comments (0)