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)