Are there support for iterator adaptors and consumers in the standard library?

I am working through Zig exercise on exercism and I just worked on an exercise whose solution was:

const std = @import("std");
pub fn score(s: []const u8) u32 {
    var final_score: u32 = 0;
    for (s) |ss| {
        final_score += point(std.ascii.toUpper(ss));
    }
    return final_score;
}

fn point(letter: u8) u32 {
   return switch(letter) {
      'A', 'E', 'I', 'O', 'U', 'L', 'N', 'R', 'S', 'T' => 1,
      'D', 'G' => 2,
      'B', 'C', 'M', 'P' => 3,
      'F', 'H', 'V', 'W', 'Y' => 4,
      'K' => 5,
      'J', 'X' => 8,
      'Q', 'Z' => 10,
      else => unreachable
    };
}

Instead of manually iterating, in Rust I could have solved it like this

pub fn score(s: &str) -> u32 {
    s.to_ascii_uppercase()
        .chars()
        .map(|letter| point(letter))
        .sum()

    // s.to_ascii_uppercase()
    //     .chars()
    //     .map(|letter| point(letter))
    //     .reduce(|acc, letter| acc + letter)
    //     .unwrap()
}

fn point(letter: char) -> u32 {
    match letter {
        'A' | 'E' | 'I' | 'O' | 'U' | 'L' | 'N' | 'R' | 'S' | 'T' => 1,
        'D' | 'G' => 2,
        'B' | 'C' | 'M' | 'P' => 3,
        'F' | 'H' | 'V' | 'W' | 'Y' => 4,
        'K' => 5,
        'J' | 'X' => 8,
        'Q' | 'Z' => 10,
        _ => panic!("unreachable"),
    }
}

Which leads me to ask the following questions,

  • In Zig’s standard library, is there support for iterators
  • Is there support for iterator adaptors like map, filter etc
  • Is there support for iterator consumers like reduce, fold, sum etc

I tried looking in the standard library but I could not find.

If the answer is “no there isn’t these kind of stuff in Zif”, my follow up question would be what is the idiomatic way in Zig to approach these kind of problems that iterator adaptors and consumers would be used for? Do it manually as I have done above?

See the Fluent library.
Showcase in ziggit: Fluent: Algorithmic Chaining Library for Slice Manipulation

3 Likes

Zig is an imperative language, and as such there is no map/reduce/fold and the like in the language or the standard library. Your Zig implementation is perfectly idiomatic. There are iterators in the standard library but they are used in an imperative way. The conventional way to implement an iterator is as a struct with a next method on it that returns an optional. This can be used in a while loop to consume elements from the iterator until the next method returns null.

var lines_iter = std.mem.tokenizeScalar(u8, file_contents, '\n');
while (lines_iter.next()) |line| {
    // Do something with `line`
}
1 Like

Well, so also is Rust :slight_smile: