Optional predicate if special logic is needed to determine whether an entry is to be removed or not.
The associative array to modify.
auto aa = [ "abc" : "def", "ghi" : string.init; "mno" : "123", "pqr" : string.init, ]; pruneAA(aa); assert("ghi" !in aa); assert("pqr" !in aa); pruneAA!((entry) => entry.length > 0)(aa); assert("abc" !in aa); assert("mno" !in aa);
1 import std.conv : text; 2 3 { 4 auto aa = 5 [ 6 "abc" : "def", 7 "ghi" : "jkl", 8 "mno" : "123", 9 "pqr" : string.init, 10 ]; 11 12 pruneAA!((a) => a == "def")(aa); 13 assert("abc" !in aa); 14 15 pruneAA!((a,b) => a == "pqr")(aa); 16 assert("pqr" !in aa); 17 18 pruneAA!`a == "123"`(aa); 19 assert("mno" !in aa); 20 } 21 { 22 struct Record 23 { 24 string name; 25 int id; 26 } 27 28 auto aa = 29 [ 30 "rhubarb" : Record("rhubarb", 100), 31 "raspberry" : Record("raspberry", 80), 32 "blueberry" : Record("blueberry", 0), 33 "apples" : Record("green apples", 60), 34 "yakisoba" : Record("yakisoba", 78), 35 "cabbage" : Record.init, 36 ]; 37 38 pruneAA(aa); 39 assert("cabbage" !in aa); 40 41 pruneAA!((entry) => entry.id < 80)(aa); 42 assert("blueberry" !in aa); 43 assert("apples" !in aa); 44 assert("yakisoba" !in aa); 45 assert((aa.length == 2), aa.length.text); 46 } 47 { 48 import std.algorithm.searching : canFind; 49 50 string[][string] aa = 51 [ 52 "abc" : [ "a", "b", "c" ], 53 "def" : [ "d", "e", "f" ], 54 "ghi" : [ "g", "h", "i" ], 55 "jkl" : [ "j", "k", "l" ], 56 ]; 57 58 pruneAA(aa); 59 assert((aa.length == 4), aa.length.text); 60 61 pruneAA!((entry) => entry.canFind("a"))(aa); 62 assert("abc" !in aa); 63 }
Iterates an associative array and deletes invalid entries, either if the value is in a default .init state or as per the optionally passed predicate.
It is supposedly undefined behaviour to remove an associative array's fields when foreaching through it. So far we have been doing a simple mark-sweep garbage collection whenever we encounter this use-case in the code, so why not just make a generic solution instead and deduplicate code?