LINQ to XML : My Version of LINQ Extension Method for IEnumerable to return Random Single Selection

I was in the middle of making so nice templates in order to generate some test data.  I wanted to create Firstnames, Lastnames and Titles but also have them specialize by sex.  So I have methods including GetMaleFirstName, GetFemaleFirstName and GetLastName.  I have three xml files which have the data in and it occurred to me that I have not yet touched on LINQ to XML, so that is what I did.  Of my collections I wanted to return a random element and also ensuring that whatever method I create I do not want to couple it , hence the reason I thought of an extension method for the IEnumerable<T> type. So the code is the following:

    public static class Extenders
    {
        public static T GetSingleRandom<T>(this IEnumerable<T> target)
        {
            Random r = new Random(DateTime.Now.Millisecond);
            int position = r.Next(target.Count<T>());
            return target.ElementAt<T>(position);
        }
    }

 

This now allows me to return a single, random, element from any IEnumerable collection.  A couple of simple tests are below.  The first one being on a simple list and the second on a XML File.

Example 1

            //Example 1
            //Simple List

            IList<string> names = new List<string>();
            names.Add("Andy");
            names.Add("Jamie");
            names.Add("John");
            names.Add("David");
            names.Add("Jo");

            Console.WriteLine(names.GetSingleRandom<string>());

 

Example 2

 

        static void Main(string[] args)
        {
            //Example 2
            //An XML Document using LINQ to XML

            string s = RandomNameAccess(@"C:\Firstnames.xml");
            Console.WriteLine(s);
            Console.ReadLine();
        }

        private static string RandomNameAccess(string fileUrl)
        {
            XDocument namesDocument = XDocument.Load(fileUrl);

            var name = from c in namesDocument.Descendants("Names")
                       select c.Elements().GetSingleRandom<XElement>().Value;

            return name.Single<string>();
        }

I know that Visual Studio Team Edition for Database Developer has a Test Data Generator but I cannot seem to get it enabled on my version. 

 

Cheers,

Andrew

Published Thursday, August 28, 2008 11:13 AM by REA_ANDREW
Filed under: , ,

Comments

# re: LINQ to XML : My Version of LINQ Extension Method for IEnumerable to return Random Single Selection

Thursday, August 28, 2008 7:16 AM by Michael Hart

You shouldn't be creating a random generator each call. Create the Random as a static property (and the default constructor would be fine).

# funny wallpaper &raquo; LINQ to XML : My Version of LINQ Extension Method for IEnumerable to return Random Single Selection

Pingback from  funny wallpaper &raquo; LINQ to XML : My Version of LINQ Extension Method for IEnumerable to return Random Single Selection

# re: LINQ to XML : My Version of LINQ Extension Method for IEnumerable to return Random Single Selection

Thursday, August 28, 2008 7:27 AM by REA_ANDREW

Cool, thanks Michael, so:

   public static class Extenders

   {

       public static Random r = new Random();

       public static T GetSingleRandom<T>(this IEnumerable<T> target)

       {

           int position = r.Next(target.Count<T>());

           return target.ElementAt<T>(position);

       }

   }

Cheers for the heads up. :-)

Andrew

# re: LINQ to XML : My Version of LINQ Extension Method for IEnumerable to return Random Single Selection

Friday, August 29, 2008 2:33 AM by Omer van Kloeten

You're iterating on the target twice - once to get the count and once to get the random item.

I would change the code to:

T[] array = target.ToArray();

int position = r.Next(array.Length);

return array[position];

Also, you may want to note that this isn't for every occasion. If the target is an IQueryable against a database, you may be better off with your extension method (SELECT COUNT(*), SELECT [...] WHERE Id = @Id) instead of my suggestion (SELECT *), but this requires further investigation.

# re: LINQ to XML : My Version of LINQ Extension Method for IEnumerable to return Random Single Selection

Saturday, August 30, 2008 9:33 AM by James Curran

I was going to make the same point as Omar:  Both Count() and ElementAt are O(N) for IEnumerable objects.  Unfortunately, Omar's solution just makes matters worse -- He trades two quick loops for one slow loop.

The good news here is the Microsoft realized this problem an optimized the extension methods-- For both Count & ElementAt, if the IEnumerable this object is really a more powerful collection, then it will use the available O(1) method, and if it's just an IEnumerable, it will fall back to the O(N) option.

The bottom line is that the way your examples are written, they are running at full speed, but if you changed the object operated on, it could suddenly get much slower.

Leave a Comment

(required) 
(required) 
(optional)
(required)