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:
- Encapsulate data formatting logic in a reusable class.
- Dynamically calculate the number of columns based on the available width.
- 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
-
Encapsulation:
- The grid formatting logic will be wrapped inside the
GridFormatter
class, ensuring reusability and separation of concerns.
- The grid formatting logic will be wrapped inside the
-
Dynamic Column Calculation:
- The number of columns will adjust dynamically based on the total width and the width of the data items.
-
Flexibility:
- The
GridFormatter
will work with any data type, making it generic and versatile.
- The
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); } } }
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); } } }
Step 3: Run the Program
Input:
Data: Alice, Bob, Charlie, Diana, Eve Total Width: 30 Gap Width: 3
Output:
Formatted Grid: Alice Bob Charlie Diana Eve
How It Works
-
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.
- The
-
Row Generation:
- Data is split into rows, each containing the appropriate number of items.
-
Padding and Spacing:
- Each item is padded to ensure consistent column alignment.
Takeaways
-
Encapsulation:
- The
GridFormatter
encapsulates all logic related to grid formatting, making it reusable across projects.
- The
-
Flexibility:
- By using generics, the
GridFormatter
can work with any type of data.
- By using generics, the
-
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)