Two algorithms
Two small code fragments for problems I found interesting.
First, I had a list of criteria that were being used to decide which files in a file list to mark as selected. Some of the criteria were simple, like "none" or "all", but some of them were more complex, like "modified in the last 15 minutes". Since I strongly disliked the idea of a series of if
s (or the equivalent switch
statement), I came up with the following:
var filters = new Dictionary<string, Predicate<FileObject>> { {"None", file => false}, {"All (*.*)", file => true}, {"Invert Selection", file => !file.Selected}, {"Modified Last 15min", file => file.LastWriteTime.AddMinutes(15) >= DateTime.Now}, {"Modified Today", file => file.LastWriteTime.Date == DateTime.Now.Date}, {"*.dll (not Telerik)", file => !file.Name.StartsWith("Telerik") && file.Name.EndsWith(".dll")}, }; foreach (var file in fileList) file.Selected = filter(file);
Of course, this is rather specific to the exact problem I had, but the idea can be used in the more general case: create one of
Dictionary<string, Predicate<T>> Dictionary<string, Func<T, TResult>> Dictionary<string, Action<T>>
and then iterate through the list and get the result / apply the action for each item. This is much easier to understand and modify than a complicated series of if
s, if only because the tendency when modifying the if
s is to add ad-hoc code to solve the particular problem you have right now instead of trying to preserve the code structure.
The second problem I had had to do with formatting a file size to the closest approximation in bytes, KB, MB or GB. For example, a 345 byte file would return "345 bytes", while a 345,000 byte file would say "336.91 KB". (1 KB = 1024 bytes.)
This is again a problem that would normally be solved with a succession of if
s, so once again I looked for something else. (One of the things I've read and that stuck with me was: if possible, move logic out of code and into data.) Here's what I came up with:
public static string Prettify(this long size) { var formats = new List<string> { "#,##0 bytes", "#,##0.## KB", "#,##0.## MB", "#,##0.## GB", }; var limit = 1024L; var index = 0; while (size >= limit) { limit *= 1024L; index++; } var format = formats[index]; return ((double) size / limit * 1024.0).ToString(format); }
The reason for the multiplication with 1024 at the end is due to the fact that the limit has already been multiplied once; what I'm doing is basically dividing it back down: size / (limit / 1024)
, I've just opened the parenthesis.
So, here they are: alternative algorithms for problems normally solved with multiple if
s.
Comments