Search code examples
c#.netlinqenumerable

How to deal with multiple Enumerable.Zip calls?


I have several enumerables with data from sensors

time_elapsed, speed_x, speed_y, speed_z, altitude, latitude, longitude…

Every list has the same number of elements.

I want to combine the data of all the lists into a sequence of Status items.

class Status 
{
    public int TimeElapsed {get; set; }
    public double SpeedX {get; set; }
    public double SpeedY {get; set; }
    public double SpeedZ {get; set; }
   ...
}

I thought about using the Enumerable.Zip method, but it looks really cumbersome:

var statuses = time_elapsed
    .Zip(speed_x, (a, b) => new { a,  b})
    .Zip(speed_y, (c, d) => new { c,  d})
    .Zip(speed_z, (e, f) => new { e , f})
    .Select(x => new Status
    {
        Time = x.e.c.a,
        SpeedX = x.e.c.b,
        SpeedY = x.e.d,
        SpeedZ = x.f
        // ...
    });

As you see, it's from from being readable with all those anonymous types.

Is there a better way to do it without losing your head?


Solution

  • Not much that you can do here, but you can improve readability and remove one anonymous type:

    var statuses = time_elapsed
        .Zip(speed_x, (time, speedX) => new {time, speedX})
        .Zip(speed_y, (x, speedY) => new {x.time, x.speedX, speedY})
        .Zip(speed_z, (x, speedZ) => new Status
        {
            TimeElapsed = x.time,
            SpeedX = x.speedX,
            SpeedY = x.speedY,
            SpeedZ = speedZ
        });
    

    You could also use this approach:

    int minSize = new IList[] {time_elapsed, speed_x, speed_y, speed_z}.Min(c => c.Count);
    IEnumerable<Status> statuses = Enumerable.Range(0, minSize)
        .Select(i => new Status
        {
            TimeElapsed = time_elapsed[i],
            SpeedX = speed_x[i],
            SpeedY = speed_y[i],
            SpeedZ = speed_z[i],
        });