Ideomatic reverse iteration

What’s the best method of iterating backwards through a slice or other iterable item? I know that for a slice or other directly indexed collection I can do it by looking at the length and using an index counter, but it seems a little clumsy and sort of defeats the point of having iterators. Some languages have reverse iterators - is there something similar for Zig?

1 Like

I don’t think there’s anything baked into the language or stdlib for this, except for std.mem.reverse() which swaps elements in place instead of just iterating over them.

5 mins hacked up custom thing to iterate in reverse:

$ cat reverse.zig 
const std = @import("std");

fn ReverseIterator(comptime Container: type) type {
    return struct {
        items: Container,
        current: usize = 0,

        pub fn next(self: *@This()) ?std.meta.Child(Container) {
            if (self.current >= self.items.len) return null;
            self.current += 1;
            return self.items[self.items.len - self.current];
        }
    };
}

fn reverse(items: anytype) ReverseIterator(@TypeOf(items)) {
    return .{ .items = items };
}

pub fn main() void {
    const things: []const u8 = &.{ 1, 2, 3, 4, 5 };
    var it = reverse(things);
    while (it.next()) |n| {
        std.log.info("{d}", .{n});
    }
}

$ zig run reverse.zig 
info: 5
info: 4
info: 3
info: 2
info: 1
3 Likes

Thank you. Looks useful. There’s a couple of things in that which are new to me as well (such as std.meta.Child) so it’s quite informative.

1 Like