Using LINQ to select random XML node

I am new to LINQ and I have a problem. I have a file that looks something like this:

<?xml version="1.0" encoding="utf-8" ?> <Galleries> <Gallery ID="10C31804CEDB42693AADD760C854ABD" Title="Test1"> <Description>The first test gallery. Picture of a cat and Wilford Brimley. Can you tell the difference?</Description> <Images> <Image Title="t1Image1" FileName="tcats.jpg" /> <Image Title="t1Image2" FileName="twb.jpg" /> </Images> </Gallery> <Gallery ID="0420EC15405B488E1E0F157AC823A6" Title="Test2"> <Description>The second test gallery. A large image of Wilford Brimley and various cats. The cats will be on the right.</Description> <Images> <Image Title="t2Image1" FileName="wilfordbrimley.jpg" /> </Images> </Gallery> </Galleries> 

In any case, I know the ID of the gallery that I want, but I want to choose one of the images at random. Is there a LINQ instruction that can do this?

+3
source share
3 answers

You can order images in the Random.Next () gallery, and then select the first item.

I don't know much about linq2xml, but here is what I came up with

 static void Main(string[] args) { Random rnd = new Random(); XDocument galleries = XDocument.Load(@"C:\Users\John Boker\Documents\Visual Studio 2008\Projects\ConsoleApplication1\ConsoleApplication1\Galleries.xml"); var image = (from g in galleries.Descendants("Gallery") where g.Attribute("ID").Value == "10C31804CEDB42693AADD760C854ABD" select g.Descendants("Images").Descendants("Image").OrderBy(r=>rnd.Next()).First()).First(); Console.WriteLine(image); Console.ReadLine(); } 

I am sure that the choice could be made differently, but this is what I did to make it work with a random event.

+3
source

Here are a couple of solutions that rely on computing the number of Image nodes; not very efficient, but I don’t think you can do better, since many Linq collection types display as IEnumerable .

 XElement GetRandomImage(XElement images) { Random rng = new Random(); int numberOfImages = images.Elements("Image").Count(); return images.Elements("Image").Skip(rng.Next(0, numberOfImages)).FirstOrDefault(); } XElement GetRandomImage(XElement images) { Random rng = new Random(); IList<XElement> images = images.Elements("Image").ToList(); return images.Count == 0 : null ? images[rng.Next(0, images.Count - 1)]; } 
+1
source

I do not recommend using the selected answer, since it uses the O(n log n) sort, where n is the number of images in the selected gallery. You can select a random item from a list in O(1) time. So I would use the following:

 using(StreamReader sr = new StreamReader(File.Open(path, FileMode.Open))) { XDocument galleries = XDocument.Load(sr); string id = "10C31804CEDB42693AADD760C854ABD"; var query = (from gallery in galleries.Descendants("Galleries") .Descendants("Gallery") where (string)gallery.Attribute("ID") == id select gallery.Descendants("Images") .Descendants("Image") ).SingleOrDefault(); Random rg = new Random(); var image = query.ToList().RandomItem(rg); Console.WriteLine(image.Attribute("Title")); } 

Here I use:

 static class ListExtensions { public static T RandomItem<T>(this List<T> list, Random rg) { if(list == null) { throw new ArgumentNullException("list"); } if(rg == null) { throw new ArgumentNullException("rg"); } int index = rg.Next(list.Count); return list[index]; } } 
0
source

Source: https://habr.com/ru/post/1346323/


All Articles