DEV Community

Marcin Scholke Szolke
Marcin Scholke Szolke

Posted on

Defragmenting Lists and Arrays in C#: Closing Gaps in Object Collections

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.

Diagram showing list defragmentation before and after closing gaps

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[] array The collection to be defragmented.
  • Func<T, bool> isEmptyOrDefaultElement A 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]
Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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;
    });

Enter fullscreen mode Exit fullscreen mode

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)