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)