Skip to Content
Course content
Click on the "Edit" button in the top corner of the screen to edit your slide content.

I was working on a telemetry project the other day where I had two separate arrays coming off a hardware sensor: one containing timestamps and another containing the actual temperature readings. They were perfectly aligned by index, but they were separate collections. My first instinct was to just use a for loop with an index i to pair them up, but that always feels a bit "C-style" and clunky when we have LINQ at our disposal.

Pairing lists without the index noise

Let's look at what I started with. I've got my timestamps and my values:

var timestamps = new[] { "10:00", "10:01", "10:02", "10:03", "10:04" };
var readings = new[] { 22.5, 22.7, 22.1, 23.0, 22.8 };

If I want to combine these into a single object or a tuple, I could do this:

var combined = new List<string>();
for (int i = 0; i < timestamps.Length; i++)
{
    combined.Add($"{timestamps[i]} -> {readings[i]}");
}

It works, sure. But it's brittle. If readings happens to be shorter than timestamps, this throws an IndexOutOfRangeException. I have to add manual checks. This is exactly why Zip exists. I tried swapping the loop for Zip, and it cleaned up the logic immediately:

var paired = timestamps.Zip(readings, (time, temp) => new { time, temp });

foreach (var item in paired)
{
    Console.WriteLine($"At {item.time}, the temp was {item.temp}");
}

The beauty here is that Zip stops as soon as the shortest sequence ends. No more manual bounds checking. I just tell it: "Take this sequence and that sequence, and here is the function to merge them."

Dealing with API batch limits

Now, here is where it got annoying. I needed to send these paired readings to a remote logging API, but the API has a strict limit: it only accepts a maximum of 2 readings per request. If I send the whole list, I get a 400 Bad Request.

My initial thought was to use Skip() and Take() inside a while loop. I started sketching it out:

int batchSize = 2;
for (int i = 0; i < paired.Count(); i += batchSize)
{
    var batch = paired.Skip(i).Take(batchSize);
    // Send batch to API...
}

Wait, that's actually pretty inefficient. Skip(i) has to iterate through the first i elements every single time. For a small list, it's fine, but if I'm processing thousands of sensor readings, I'm wasting a lot of cycles. I remember seeing a newer method in .NET called Chunk. Let's see if it does what I think it does.

I replaced the loop with this:

var batches = paired.Chunk(2);

foreach (var batch in batches)
{
    Console.WriteLine("--- New API Request ---");
    foreach (var reading in batch)
    {
        Console.WriteLine($"{reading.time}: {reading.temp}");
    }
}

That's much cleaner. Chunk doesn't just skip and take; it slices the sequence into arrays of the size you specify. If the total number of elements isn't perfectly divisible by the chunk size, the last chunk is just smaller—it doesn't crash or pad it with nulls. It just gives you what's left.

The final pipeline

When you put them together, you get this really elegant flow: you zip your disparate data sources into a unified model, then chunk that model into the exact sizes your external dependencies require. It turns a messy set of loops and index counters into a declarative pipeline.

var telemetryData = timestamps
    .Zip(readings, (time, temp) => new { time, temp })
    .Chunk(2);

// Now we have an IEnumerable of arrays, ready for the API.



📋 Practical Task

Building a Paginated User-Role Mapper

You have two lists: one containing usernames and one containing assignedRoles. The lists are sorted such that the username at index 0 belongs to the role at index 0, and so on.

Your task is to create a program that:

  1. Uses Zip to pair the usernames and roles into a tuple or an anonymous object.
  2. Uses Chunk to divide these pairs into "pages" of 3 users per page.
  3. Prints each page to the console, clearly labeling the page number (e.g., "Page 1", "Page 2") and listing the users and their roles within that page.

Starter Data:

string[] usernames = { "Alice", "Bob", "Charlie", "Dan", "Eve", "Frank", "Grace", "Heidi" };
string[] roles = { "Admin", "User", "User", "Editor", "Admin", "User", "Editor", "User" };
Rating
0 0

There are no comments for now.

to be the first to leave a comment.