Static Maps

I need to create a map with amino acids as keys and values that represent their mass (f32). Amino acids, the building blocks of proteins, are represented by a single capital letter–there are just 20 of them. I created the working solution below that uses string keys, but is there something similar that allows use of a single u8 value as the key?

const massMap = std.StaticStringMap(f32).initComptime([_]struct { []const u8, f32 }{
    .{ "A", 71.07855 },  .{ "C", 103.14464 }, .{ "D", 115.08826 }, .{ "E", 129.11504 },
    .{ "F", 147.17571 }, .{ "G", 57.05177 },  .{ "H", 137.14062 }, .{ "I", 113.15890 },
    .{ "K", 128.17358 }, .{ "L", 113.15890 }, .{ "M", 131.19820 }, .{ "N", 114.10354 },
    .{ "P", 97.11623 },  .{ "Q", 128.13032 }, .{ "R", 156.18707 }, .{ "S", 87.07796 },
    .{ "T", 101.10474 }, .{ "V", 99.13211 },  .{ "W", 186.21220 }, .{ "Y", 163.17512 },
});
2 Likes

You could use an array for integer keys to any other type:

const massMap = blk: {
    var map: [91]f32 = undefined; // 'Z' is 90
    map['p'] = 3.14159;
    ...
    break :blk map;
};
1 Like

make an enum for the names, and use a std.EnumArray to map them to the float values.

const AminoAcid = enum {
   A,
   F,
   //...
};

const massMap: std.EnumArray(AminoAcid, f32) = .init(.{
    .A = 71.07855, .F = 147.17571,
    //...
});

const A_mass = massMap.get(.A);
14 Likes

Your use case sounds simple enough that you should probably be able to handroll something.

For example let’s say I want to map keys that are an alphabetical character from ‘A’ to ‘Z’ you can probably do it like this:

fn MyMap(V: type) {
    return struct{
       arr: [N]V; 
       const N = 'Z' - 'A';
       
       fn get(self: *@This(), key: u8) *V {
            std.debug.assert(key >= 'A' and key <= 'Z');
            return &self.arr[key - 'A'];
       }
    };
}

Obviously this is super minimal, you add features as you need them.

2 Likes

Wow, thank you for the quick and excellent responses. I’m new to zig and low level programming so I will enjoy trying all three approaches.

1 Like

Slightly off-topic, but in Java I’d use BigDecimal for those type of values. Not sure if Zig has the equivalent?

std.math.int.big contains arbitrarily large integers!

1 Like

Typo in description: s/EnumArray/EnumMap/

Oops, fixed it.

EnumMap also exists, the difference is the map can have unset values, the array can’t.

2 Likes