IEnumerable Приведение 2 IEnumerables к одному классу

У меня есть 2 IEnumerables

IEnumerable<float> Distance
IEnumerable<XElement> Point

который я хочу преобразовать в

IEnumerable<Subsection> subsection

где класс

class Subsection
{
    public float Distance
    public XElement Point
}

Но я понятия не имею, как это сделать, я пробовал несколько вариантов приведения, ни один из которых не работал, потому что они, похоже, не принимают несколько списков в качестве входных данных.

Переменные Distance и Point считываются из XML-документа, где структура этих двух точек аналогична следующей:

<PLI>
    <Distance>5</Distance>
    <Point>23 22</Point>
    <Distance>7</Distance>
    <Point>21 72</Point>
    <Distance>9</Distance>
    <Point>13 32</Point>
</PLI>

Я не был уверен, как прочитать их просто как тип подраздела, но если бы кто-нибудь мог предложить, как это сделать, это обошло бы мою необходимость преобразовать его, поскольку у меня больше не будет их как IEnumerables расстояния и точки, а как структура .

Обратите внимание, что я не могу изменить XML

Спасибо

EDIT: XML содержит другие элементы, а также те, которые упомянуты в теге PLI, например.

<PLI>
    <OtherElement1>element1value</OtherElement1>
    <OtherElement2>element2value</OtherElement2>
    <Distance>5</Distance>
    <Point>23 22</Point>
    <Distance>7</Distance>
    <Point>21 72</Point>
    <Distance>9</Distance>
    <Point>13 32</Point>
</PLI>

person Manatherin    schedule 13.12.2010    source источник
comment
Обновил мой пост, чтобы учесть другие элементы. Это затронуло только не-LINQ-подход. Подход Zip не изменился.   -  person Ahmad Mageed    schedule 13.12.2010


Ответы (2)


Это можно сделать с помощью LINQ с помощью метода Enumerable.Zip при условии, что ваш XML сбалансирован (четное количество элементов для сопоставления расстояний и точек).

var query = xml.Elements("Distance")
               .Zip(xml.Elements("Point"),
                    (d, p) => new Subsection
                    {
                        Distance = float.Parse(d.Value),
                        Point = p
                    });

В качестве альтернативы вы можете перебирать элементы и создавать Subsection элементов. Это можно сделать следующим образом, хотя предполагается, что ваш XML-документ сбалансирован и имеет ожидаемый формат.

var query = xml.Elements()
               .Where(e => e.Name.LocalName == "Distance"
                           || e.Name.LocalName == "Point");
var list = new List<Subsection>();
int count = 0;
Subsection s = null;
foreach (var element in query)
{
    if (count % 2 == 0)
        s = new Subsection { Distance = float.Parse(element.Value) };
    else
    {
        s.Point = element;
        list.Add(s);
    }

    count++;
}

Обратите внимание, что в обоих фрагментах переменная xml является XElement. Для XDocument добавьте свойство Root, как в xml.Root.Elements(...).

person Ahmad Mageed    schedule 13.12.2010
comment
Обновлен второй подход для фильтрации элементов Distance и Point и работы только с ними. Опять же, вы должны быть уверены, что они сбалансированы. Если вы не уверены, то предварительной .Count() проверки обоих наборов элементов должно быть достаточно, чтобы их сумма была четной (модуль 2 == 0). - person Ahmad Mageed; 13.12.2010
comment
Спасибо, функция zip была именно тем, что я искал, никогда раньше ее не видел - person Manatherin; 13.12.2010

Это непрозрачно с точки зрения ссылок и совершенно нецелесообразно, но если вы настроены на LINQ, это лучшая идея, которая у меня есть на данный момент для этой конкретной проблемы. Таким образом, ваш заказ гарантированно будет таким же.

public class SubSection
{
    public float Distance;
    public XElement Point;

    public SubSection(XElement distance, XElement point)
    {
        Distance = float.Parse(distance.Value);
        Point = point;
    }
}
class Program
{
    static void Main(string[] args)
    {
        var c = XDocument.Parse(@"<PLI>
<Distance>5</Distance>
<Point>23 22</Point>
<Distance>7</Distance>
<Point>21 72</Point>
<Distance>9</Distance>
<Point>13 32</Point>
</PLI>");

        var sup = new List<SubSection>();
        c.Elements().Elements().Aggregate<XElement,XElement>(null, (a, d) =>
            {
                if (a == null)
                    return d;
                sup.Add(new SubSection(a, d));
                return null;
            });
        foreach (var entry in sup)
        {
            Console.WriteLine(entry.Distance);
        }

    }
}
person Squirrelsama    schedule 13.12.2010