Search code examples
zig

Get the maximum value of any Zig hash map


I wrote the following to find the maximum value in a Zig std.AutoHashMap:

pub fn hashMinMaxValue(comptime K: type, comptime V: type, hash_map: std.AutoHashMap(K, V)) ?struct { min: V, max: V } {
    var min: V = undefined;
    var max: V = undefined;
    var it = hash_map.valueIterator();
    if (it.next()) |val| {
        min = val.*;
        max = val.*;
    } else {
        return null;
    }
    while (it.next()) |val| {
        min = @min(min, val.*);
        max = @max(max, val.*);
    }
    return .{ .min = min, .max = max };
}

pub fn hashMaxValue(comptime K: type, comptime V: type, hash_map: std.AutoHashMap(K, V)) ?V {
    const minMax = hashMinMaxValue(K, V, hash_map);
    if (minMax) |v| {
        return v.max;
    }
    return null;
}

Now I'd like to use this with a std.StringHashMap. So I copy/pasted the code and adjusted it like so:

pub fn strHashMinMaxValue(comptime V: type, hash_map: std.StringHashMap(V)) ?struct { min: V, max: V } {
    var min: V = undefined;
    var max: V = undefined;
    var it = hash_map.valueIterator();
    if (it.next()) |val| {
        min = val.*;
        max = val.*;
    } else {
        return null;
    }
    while (it.next()) |val| {
        min = @min(min, val.*);
        max = @max(max, val.*);
    }
    return .{ .min = min, .max = max };
}

pub fn strHashMaxValue(comptime V: type, hash_map: std.StringHashMap(V)) ?V {
    const minMax = strHashMinMaxValue(V, hash_map);
    if (minMax) |v| {
        return v.max;
    }
    return null;
}

This feels a little gross. Is there a good way to share logic between these? Moreover, since I only need the max value, is there a way to mark the generic key type K as "don't care"?


Solution

  • You need to use anytype. For example:

    fn find_max_value(comptime V: type, hash_map: anytype) ?V {
        var max: V = undefined;
        var it = hash_map.valueIterator();
        if (it.next()) |value| {
            max = value.*;
        }
        else {
            return null;
        }
        while (it.next()) |value| {
            max = @max(max, value.*);
        }
        return max;
    }
    

    This works for both AutoHashMap and StringHashMap.
    Take a look at Generic Data Structures in the Zig documentation for more information.