Introduction
What is this code or article about? What problem does it solve?
This article presents a generic defragmentation utility for arrays and lists in C#.
Over time, collections often become fragmented due to removals or logical deactivation of elements, leaving “holes” represented by default or empty values. Such fragmentation negatively affects iteration performance, cache locality, and overall data consistency.
The provided Defragmentation class solves this problem by compacting collections in place, moving valid elements forward and closing gaps without changing the collection size. The solution works for primitive types as well as complex objects and allows custom rules for detecting empty elements and copying object data safely.
How To Use
How do you implement or use the code? What are the key classes, methods, or parameters?
The core of the solution is the generic static class:
Defragmentation
It exposes several overloaded Defragment methods that work with:
IList<T>T[] arrays
Key parameters:
-
IList<T> list / T[] arrayThe collection to be defragmented. -
Func<T, bool> isEmptyOrDefaultElementA predicate that defines when an element should be treated as a “gap”. -
Action<T, T> copyFromSourceToDestination(optional) A custom copy strategy for complex objects when reference swapping is not desired.
The algorithm scans the collection from the end and swaps non-empty elements with empty ones found earlier in the collection. It returns true if at least one replacement was performed.
Code Example
Working example with brief comments
Defragmenting a list of primitive values
IList<int> list = new List<int> { 0, 0, 1, 0, 1, 1 };
// Move all non-zero values to the front
Defragmentation<int>.Defragment(list, x => x == 0);
// Result: [1, 1, 1, 0, 0, 0]
Defragmenting a list of objects
IList<Foo> list = new List<Foo>
{
new Foo(0, "empty"),
new Foo(1, "valid"),
new Foo(0),
new Foo(1, "last")
};
// Treat objects with Count == 0 as empty
Defragmentation<Foo>.Defragment(list, x => x.Count == 0);
// Valid objects are moved to the front, empty ones to the end
Defragmenting with custom copy logic
Defragmentation<Foo>.Defragment(
array,
x => x.Count == 0,
(source, destination) =>
{
destination.Count = source.Count;
destination.Name = source.Name ?? string.Empty;
});
This variant is useful when working with complex objects that should not be swapped by reference but instead copied field by field.

Top comments (0)