Thursday, January 29, 2009

C# Puzzle No.12 (intermediate)

Consider following class which stores the information about external urls.

   1: class LinkInfo
   2: {
   3:      public int    Ord { get; set; }
   4:      public string Url { get; set; }
   5: }

In your application you somehow retrieve the list of such items:



   1: List<LinkInfo> l = new List<LinkInfo>()
   2:      { 
   3:        new LinkInfo() { Ord = 1, Url = "" },
   4:        new LinkInfo() { Ord = 2, Url = "test1" },
   5:        new LinkInfo() { Ord = 3, Url = "test1" },
   6:        new LinkInfo() { Ord = 4, Url = "test2" },
   7:        new LinkInfo() { Ord = 5, Url = "" }
   8:      };

Your goal is to use Linq to filter this list in a special way:



  • if the Url is empty - the item is always returned

  • if the Url is nonempty - only one item with such Url is returned

In the above case the Linq expression should return:



   1: { 
   2:   new LinkInfo() { Ord = 1, Url = "" },
   3:   new LinkInfo() { Ord = 2, Url = "test1" },
   4:   new LinkInfo() { Ord = 4, Url = "test2" },
   5:   new LinkInfo() { Ord = 5, Url = "" }
   6: };

or



   1: { 
   2:   new LinkInfo() { Ord = 1, Url = "" },
   3:   new LinkInfo() { Ord = 3, Url = "test1" },
   4:   new LinkInfo() { Ord = 4, Url = "test2" },
   5:   new LinkInfo() { Ord = 5, Url = "" }
   6: }

 


How effective is your solution? Can you not only think of just a solution but of an effective one?

2 comments:

Krzysiek Olejniczak said...

It's not written if elements in returned list should be ordered by Ord property :-). If they don't need to be sorted, I would use following Linq expression:

var result = l.GroupBy(li => li.Url).SelectMany(g => (g.Key == string.Empty) ? g.ToArray() : new[] { g.First() });

I would say, that the source list of url addresses will be iterated once, so it should be effective. Am I rigth?

Regards

Wiktor Zychla said...

nice one! this is exactly the code I came up with.

Regards