One of the things that has always frustrated me about programming in C# that it is such a hassle to return multiple values from a method. You either have to create a wrapper class whose entire purpose is to hold two or three variables or even worse use ref or out parameters. I used to get around this problem in C++ by using the pair utility class since I often wanted to deal with an object plus some value associated with it. However this approach quickly breaks down when you have more than two objects you want to associate temporarily for some processing.
For example, in the Top Stories feature of RSS Bandit I have some code that operates on a URL, its weighted score and a list of all the posts that reference it. In C#, there’s no good way to deal with those three objects as a single entity without wrapping them in a class definition. In Python, it’s quite easy to do that using tuples. Compare the following two blocks of code and notice how I don’t need the RelationHrefEntry and RankedNewsItem types in the Python version of the code
RelationHrefEntry
RankedNewsItem
C#: /* Tally the votes, only 1 vote counts per feed */
//RelationHrefEntry is (Href, Score, References), RankedNewsItem is (NewsItem, Score)List<RelationHRefEntry> weightedLinks = new List<RelationHRefEntry>(); foreach (KeyValuePair<RelationHRefEntry, List<RankedNewsItem>> linkNvotes in allLinks) { Dictionary<string, float> votesPerFeed = new Dictionary<string, float>(); //pick the lower vote if multiple links from a particular feed foreach (RankedNewsItem voteItem in linkNvotes.Value) { string feedLink = voteItem.Item.FeedLink; if(votesPerFeed.ContainsKey(feedLink)){ votesPerFeed[feedLink] = Math.Min(votesPerFeed[feedLink], voteItem.Score); }else{ votesPerFeed.Add(feedLink, voteItem.Score); linkNvotes.Key.References.Add(voteItem.Item); } } float totalScore = 0.0f; foreach (float value in votesPerFeed.Values) { totalScore += value; } linkNvotes.Key.Score = totalScore; weightedLinks.Add(linkNvotes.Key); } weightedLinks.Sort(delegate(RelationHRefEntry x, RelationHRefEntry y) { return y.Score.CompareTo(x.Score);} ); weightedLinks = weightedLinks.GetRange(0, numStories);
//RelationHrefEntry is (Href, Score, References), RankedNewsItem is (NewsItem, Score)
List<RelationHRefEntry> weightedLinks = new List<RelationHRefEntry>();
foreach (KeyValuePair<RelationHRefEntry, List<RankedNewsItem>> linkNvotes in allLinks) {
Dictionary<string, float> votesPerFeed = new Dictionary<string, float>();
//pick the lower vote if multiple links from a particular feed
foreach (RankedNewsItem voteItem in linkNvotes.Value) {
string feedLink = voteItem.Item.FeedLink;
if(votesPerFeed.ContainsKey(feedLink)){
votesPerFeed[feedLink] = Math.Min(votesPerFeed[feedLink], voteItem.Score);
}else{
votesPerFeed.Add(feedLink, voteItem.Score);
linkNvotes.Key.References.Add(voteItem.Item);
}
float totalScore = 0.0f;
foreach (float value in votesPerFeed.Values) {
totalScore += value;
linkNvotes.Key.Score = totalScore;
weightedLinks.Add(linkNvotes.Key);
weightedLinks.Sort(delegate(RelationHRefEntry x, RelationHRefEntry y) { return y.Score.CompareTo(x.Score);} );
weightedLinks = weightedLinks.GetRange(0, numStories);
Python:
# tally the votes, only 1 vote counts per feed weighted_links = [] for link, votes in all_links.items(): site = {} for weight, item, feedTitle in votes: #tuple magic happens here site[feedTitle] = min(site.get(feedTitle,1), weight) #Python dictionaries are smarter than .NET’s weighted_links.append((sum(site.values()), link)) #more tuple magic, no need for manual summing of values weighted_links.sort() weighted_links.reverse()
Now playing: UGK - One Day