Использование LINQ для выбора случайного узла XML - PullRequest
3 голосов
/ 14 января 2010

Я новичок в LINQ и у меня проблема. У меня есть файл, который выглядит примерно так:

<?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> 

В любом случае, я знаю идентификатор Галереи, которую хочу, но хочу выбрать одно из изображений случайным образом. Есть ли оператор LINQ, который может это сделать?

Ответы [ 3 ]

3 голосов
/ 14 января 2010

Вы можете заказать изображения в галерее методом Random.Next (), а затем выбрать первый элемент.

Я не знаю много о linq2xml, но вот что я придумал

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();
}

Я уверен, что выбор может быть сделан по-другому, но это то, что я сделал, чтобы он работал с функцией random.next.

1 голос
/ 14 января 2010

Вот пара решений, которые полагаются на вычисление количества Image узлов; не очень эффективно, но я не думаю, что вы можете добиться большего успеха, поскольку многие типы коллекций Linq представлены как 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)];
}
0 голосов
/ 14 января 2010

Я не рекомендую использовать выбранный ответ, так как он использует сортировку O(n log n), где n - количество изображений в выбранной галерее Вы можете выбрать случайный элемент из списка в O(1) времени. Таким образом, я бы использовал следующее:

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"));
}

Здесь я использую:

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];
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...