Arrays 101 for LLM Power Users — From Basics to “Token‑Efficient Thinking” (with C# Examples)
Arrays are one of those “basic” topics everyone thinks they already know… until they start building with LLMs.
Then suddenly you care about things like:
- Why does a slice allocate?
- How can I format data so the model “gets it” with fewer tokens?
- Why does chunking work better with fixed-size windows?
- How do arrays relate to vector embeddings, context windows, and retrieval?
In this post we’ll refresh core array fundamentals and then connect them to how you use LLMs effectively: prompt design, chunking strategies, memory layout intuition, and performance patterns in .NET.
You’ll leave with:
- A clean mental model of arrays (1D, 2D, jagged)
- Practical patterns (search, map, filter, reduce)
- The “LLM lens”: chunking, token budget, structured serialization
- Token-efficient formatting patterns (arrays → compact text)
- Performance + memory notes (cache friendliness, allocations, bounds checks)
- GitHub-ready C# examples and pro tips
Table of Contents
- Mental Model: What an Array really is
- Array Basics in C#: creation, indexing, length
- 1D vs 2D vs Jagged: when to use which
- Traversal patterns: loops, foreach, Span
- Common algorithms: search, copy, resize, sort
- Arrays for LLM work: chunking, windows, embeddings prep
- Token-efficient formatting: arrays → compact text
- Performance notes: cache, bounds checks, allocations
- Production checklist
1) Mental Model: What an Array really is
An array is:
A contiguous block of memory containing elements of the same type, accessible by index.
Key properties:
- Fixed size once created
- O(1) random access by index
- Strong memory locality → CPU cache friendly
- In .NET,
T[]is a reference type object that contains:- an object header
- the array length
- the contiguous element region
When you index arr[i], the runtime does:
1) bounds check (unless optimized away)
2) address calculation: base + i * sizeof(T)
3) load/store
This is why arrays are extremely fast.
2) Array Basics in C
2.1 Create arrays
int[] numbers = { 1, 2, 3, 25 };
string[] names = new[] { "Juan", "Luis", "Diana" };
var zeros = new int[10]; // fixed length, initialized to 0
2.2 Indexing and length
Console.WriteLine(numbers[0]); // 1
Console.WriteLine(numbers.Length); // 4
numbers[1] = 200; // update
2.3 Bounds checks
// throws IndexOutOfRangeException
// Console.WriteLine(numbers[999]);
Modern JIT can remove bounds checks in tight loops, but only when it can prove safety.
3) 1D vs 2D vs Jagged Arrays (and why it matters)
3.1 One-dimensional (T[])
Best default: compact, fast, simple.
3.2 Rectangular multi-dimensional (T[,])
True 2D grid:
int[,] grid = new int[3, 4];
grid[1, 2] = 99;
Tradeoff: indexing costs can be higher than T[] because the runtime must compute offsets for multiple dimensions.
3.3 Jagged (T[][])
Array of arrays:
int[][] jagged = new int[3][];
jagged[0] = new[] { 1, 2 };
jagged[1] = new[] { 3, 4, 5 };
jagged[2] = new[] { 6 };
Tradeoff: not contiguous across rows, but often faster and more flexible than [,] for “rows of variable length”.
LLM note: jagged arrays map well to “chunks of chunks”: document → paragraphs → sentences.
4) Traversal Patterns
4.1 for loop (fastest control)
for (int i = 0; i < numbers.Length; i++)
{
Console.WriteLine(numbers[i]);
}
4.2 foreach (clean)
foreach (var n in numbers)
{
Console.WriteLine(n);
}
4.3 Span: “array view” without allocations
Span<int> window = numbers.AsSpan(1, 2); // slice [numbers[1], numbers[2]]
window[0] = 777;
This is gold for performance and for chunking windows (more on that soon).
5) Common Array Algorithms (you’ll use these everywhere)
5.1 Linear search (O(n))
static int IndexOf<T>(T[] arr, T value)
{
for (int i = 0; i < arr.Length; i++)
if (EqualityComparer<T>.Default.Equals(arr[i], value))
return i;
return -1;
}
5.2 Copy
var copy = new int[numbers.Length];
Array.Copy(numbers, copy, numbers.Length);
5.3 Sort
Array.Sort(numbers);
5.4 Resize (allocates new array)
Array.Resize(ref numbers, numbers.Length + 10);
Arrays are fixed-size. Resizing means: allocate new → copy → replace reference.
6) Arrays for LLM Work: Chunking, Sliding Windows, and Token Budgets
Here’s the big unlock: LLMs operate over sequences (tokens). Arrays are your tool for structuring sequences before you serialize to prompts.
6.1 Chunking documents into arrays
When you chunk a document for RAG:
- You split the text into segments (chunks)
- Each chunk becomes an element in
string[] chunks - You embed those chunks into vectors
Why arrays? Because they give you:
- deterministic order
- stable indices / IDs
- fast slicing into windows
Example:
string[] chunks = ChunkByChars(text, chunkSize: 1200, overlap: 200);
6.2 Sliding window (overlap) is literally array slicing
LLMs need overlap to keep context continuity:
- chunk 0: chars 0..1200
- chunk 1: chars 1000..2200
- chunk 2: chars 2000..3200
That overlap is a window concept — which maps directly to Span<T> windows.
6.3 Chunking is a “locality” strategy
Chunking works because:
- you reduce irrelevant noise
- you feed the model compact, relevant context
- you stay within context window limits
Arrays make chunking reproducible, testable, and performant.
7) Token‑Efficient Formatting: Arrays → Compact Text That Models Understand
Most people waste tokens by dumping unstructured text.
Instead, treat your prompt like a compact serialization problem.
7.1 Bad: long prose
“Here is a bunch of data, please analyze it…”
7.2 Better: compact array-of-records
If you have call records, store them in an array of small lines:
var lines = new[]
{
"t=2025-12-10; dir=in; dur=19.0; skill=",
"t=2025-12-10; dir=out; dur=40.2; skill=sales"
};
Then in prompt:
Records:
[0] t=2025-12-10; dir=in; dur=19.0; skill=
[1] t=2025-12-10; dir=out; dur=40.2; skill=sales
Task: summarize anomalies, compute avg duration, list missing skills.
This works because:
- the model sees consistent structure
- tokens are minimized
- indices are stable → you can reference records by
[i]
7.3 A practical “LLM-ready array serializer”
static string ToLLMLines(string[] items, string header = "Items:")
{
var sb = new System.Text.StringBuilder();
sb.AppendLine(header);
for (int i = 0; i < items.Length; i++)
sb.AppendLine($"[{i}] {items[i]}");
return sb.ToString();
}
8) Performance Notes That Actually Matter
8.1 CPU cache friendliness
Arrays are contiguous → better cache locality → faster loops.
This matters when you:
- compute embeddings
- pre-process large corpora
- normalize tokens
- batch requests
8.2 Allocation awareness
-
Array.Resizeallocates -
string.Splitallocates - LINQ can allocate (enumerators, closures, intermediate collections)
For high-volume pipelines, prefer:
-
Span<T>/ReadOnlySpan<T> ArrayPool<T>- simple loops
8.3 Bounds-check elimination
JIT can remove bounds checks in patterns like:
for (int i = 0; i < arr.Length; i++) { /* arr[i] */ }
But if you index with non-obvious expressions, the JIT may keep checks.
9) A GitHub‑Ready C# Deep Dive Example (Arrays + “LLM Thinking”)
Below is a compact example you can drop into a repo to demonstrate:
- arrays
- chunking
- overlap
- serialization for prompts
using System;
using System.Collections.Generic;
using System.Text;
public static class LlmArrayPatterns
{
public static void Demo()
{
string text = new string('A', 3000); // pretend this is a big document
var chunks = ChunkByChars(text, chunkSize: 1200, overlap: 200);
Console.WriteLine($"Chunks: {chunks.Length}");
Console.WriteLine(ToLLMLines(chunks, header: "Chunk Preview:"));
}
// Basic chunker: (size, overlap) -> array of chunks.
public static string[] ChunkByChars(string input, int chunkSize, int overlap)
{
if (chunkSize <= 0) throw new ArgumentOutOfRangeException(nameof(chunkSize));
if (overlap < 0 || overlap >= chunkSize) throw new ArgumentOutOfRangeException(nameof(overlap));
var list = new List<string>();
int step = chunkSize - overlap;
for (int start = 0; start < input.Length; start += step)
{
int len = Math.Min(chunkSize, input.Length - start);
list.Add(input.Substring(start, len));
if (start + len >= input.Length) break;
}
return list.ToArray();
}
// Prompt-friendly formatter: stable indices.
public static string ToLLMLines(string[] items, string header = "Items:")
{
var sb = new StringBuilder();
sb.AppendLine(header);
for (int i = 0; i < items.Length; i++)
{
var preview = items[i].Length > 40 ? items[i].Substring(0, 40) + "..." : items[i];
sb.AppendLine($"[{i}] len={items[i].Length} :: {preview}");
}
return sb.ToString();
}
}
10) Production Checklist
Before you build an LLM pipeline with “arrays everywhere”:
- [ ] Keep raw text chunks in
string[]orList<string>(then freeze to array) - [ ] Use consistent chunk size + overlap
- [ ] Preserve indices / IDs for traceability
- [ ] Serialize arrays into token-efficient formats (indexed lines)
- [ ] Avoid unnecessary allocations in hot paths (use Span, pooling)
- [ ] Write tests: chunk boundaries, overlap correctness, stable ordering
Wrap‑up
Arrays are the simplest data structure — but they’re also:
- the foundation of fast memory access
- the mental model behind windows and chunking
- the backbone of token-efficient prompt inputs
If you want, I can also generate:
- A full
.NET 8console repo with these demos - A BenchmarkDotNet suite (arrays vs LINQ vs Span)
- A “RAG chunking spec” template for your team docs
Happy building — and may your prompts be compact and your arrays cache-friendly. 🧠⚡

Top comments (1)
Loved how you connected basic array concepts to real LLM use cases like chunking, token efficiency, and prompt structuring. The Span + sliding window explanation was especially practical. Great bridge between fundamentals and modern AI workflows.