rendered paste bodyvoid init(T, U, V)(ref T[U] assoc, U where, lazy V how) { static assert(is(V: T)); if (!(where in assoc)) assoc[where]=how;}struct slope1(I, U) { /// Items and Users struct userPrefs { U user; float[I] ratings; } float[I][I] diffs; size_t[I][I] freqs; void update(userPrefs[] prefs) { foreach (entry; prefs) foreach (item, rating; entry.ratings) { init(diffs, item, (float[I]).init); init(freqs, item, (size_t[I]).init); foreach (item2, rating2; entry.ratings) { init(diffs[item], item2, 0f); init(freqs[item], item2, 0); freqs[item][item2]+=1; diffs[item][item2]+=rating-rating2; } } foreach (item, ratings; diffs) foreach (item2, rating; ratings) ratings[item2]/=freqs[item][item2]; } float[I] predict(userPrefs prefs) { float[I] preds; size_t[I] freqs; foreach (item, rating; prefs.ratings) { foreach (diffitem, diffratings; diffs) { if (!(diffitem in this.freqs) || (!(item in this.freqs[diffitem]))) continue; auto freq=this.freqs[diffitem][item]; init(preds, diffitem, 0f); init(freqs, diffitem, 0); preds[diffitem]+=freq*(diffratings[item] + rating); freqs[diffitem]+=freq; } } float[I] res; foreach (item, value; preds) if (!(item in prefs.ratings) && freqs[item]>0) res[item]=value/freqs[item]; return res; }}template constEnum(T, int start, S...) { static if(S.length) const char[] constEnum="const "~T.stringof~" "~S[0]~" = "~start.stringof~"; "~constEnum!(T, start+1, S[1..$]); else const char[] constEnum="";}import std.stdio;void main() { typedef int critters; mixin(constEnum!(critters, 0, "cuttlefish", "octupus", "squid", "nautilus")); typedef slope1!(critters, string) mySlope; mySlope s; s.update([ mySlope.userPrefs("alice", [squid: 1f, cuttlefish: .5f, octupus: .2f]), mySlope.userPrefs("bob", [squid: 1f, octupus: 0.5f, nautilus: 0.2f]), mySlope.userPrefs("carole", [squid: .2f, octupus: 1f, cuttlefish: .4f, nautilus: .4f]), mySlope.userPrefs("dave", [cuttlefish: 0.9f, octupus: 0.4f, nautilus: 0.5f]) ]); writefln(s.predict(mySlope.userPrefs("", [squid: 0.4])));}xt4100 ~/d $ gdc slope1.d -o slope1 && ./slope1[0:0.25,1:0.233333,3:0.1]