Использование LINQ для выравнивания иерархического набора данных — с оговоркой

#c# #linq

#c# #linq

Вопрос:

У меня есть следующий набор данных, который мне нужно преобразовать в список:

 <row itemID="828518871" locationID="60004165" typeID="9331" quantity="6" flag="4" singleton="0"/>
<row itemID="830476364" locationID="60004165" typeID="649" quantity="1" flag="4" singleton="1">
  <rowset name="contents" key="itemID" columns="itemID,typeID,quantity,flag,singleton">
    <row itemID="1139985051" typeID="6485" quantity="1" flag="22" singleton="1"/>
    <row itemID="1773489170" typeID="11489" quantity="1" flag="5" singleton="1">
      <rowset name="contents" key="itemID" columns="itemID,typeID,quantity,flag,singleton">
        <row itemID="1001694072954" typeID="16357" quantity="1" flag="0" singleton="0"/>
        <row itemID="1001694110421" typeID="16371" quantity="1" flag="0" singleton="0"/>
        ...
      </rowset>
    </row>
  </rowset>
  </row>
  

( ... указывает дополнительные строки и / или уровни вложенности; уровни теоретически могут вкладываться бесконечно.)

Вывод должен выглядеть следующим образом:

 Item { ID = 828518871, Location = 60004165, Type = 9331, Quantity = 6, Flag = 4, Singleton = false }
Item { ID = 830476364, Location = 60004165, Type = 649, Quantity = 1, Flag = 4, Singleton = true }
Item { ID = 1139985051, Location = 60004165, Type = 6485, Quantity = 1, Flag = 22, Singleton = true }
Item { ID = 1773489170, Location = 60004165, Type = 11489, Quantity = 1, Flag = 5, Singleton = true }
Item { ID = 1001694072954, Location = 60004165, Type = 16357, Quantity = 1, Flag = 0, Singleton = false }
Item { ID = 1001694110421, Location = 60004165, Type = 16371, Quantity = 1, Flag = 0, Singleton = false }
...
  

Загвоздка в том, что все строки в выходных данных должны быть LocationID правильно установлены — дочерние строки должны получать это свойство от своего родителя или родительского элемента своего родителя и т.д.

Я написал рекурсивный метод, который корректно генерирует требуемый вывод, но я хотел бы получить те же результаты, используя только LINQ — возможно ли это?

Ответ №1:

LINQ обычно не подходит для произвольной рекурсии. Это прекрасно подходит для выравнивания одного уровня вложенности с помощью SelectMany , но рекурсивным решениям все равно в конечном итоге потребуется вызывать себя явно. Например, вы можете написать метод, который использует LINQ и который вызывает сам себя в запросе, но вы не можете легко заставить LINQ выполнять рекурсию неявно.

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

Ответ №2:

Некоторое время назад я написал небольшой метод расширения, вызываемый SelectRecursive для IEnumerable<T> интерфейса, который вы можете использовать для создания рекурсивных запросов linq. http://www.codeproject.com/Tips/80746/Select-Recursive-Extension-method.aspx