2009-11-16 32 views
4

如何編寫一個採用分層源數據並對其進行轉換的LINQ查詢以使分組反轉?如何編寫一個反轉分層數據源分組的LINQ查詢?

假設我有一個Topic對象列表,其中每個Topic對象都包含表示該主題上的元數據標籤的標籤集合。我需要的是編寫一個LINQ查詢來基本翻轉層次結構,這樣我就可以得到一個標籤列表,其中每個標籤都有一組使用特定標籤標記的主題。

Topic { Title = "Political Debate #1", Posted = 01/02/2008 } 
    Tag { Name = "Contraversial", Color = "Red" } 
    Tag { Name = "Politics", Color = "LightBlue" } 
Topic { Title = "iPhone to support SiliverLight!", Posted = 02/23/2009 } 
    Tag { Name = "BleedingEdge", Color = "LightBlue" } 
    Tag { Name = "Contraversial", Color = "Red" } 
    Tag { Name = ".NET", Color = "LightGreen" } 
Topic { Title = "Fed Chairman admits guilt for causing second Great Depression", Posted = 06/15/2010 } 
    Tag { Name = "Politics", Color = "LightBlue" } 
    Tag { Name = "Contraversial", Color = "Red" } 

我希望上述數據看起來像下面的結果。

Tag { Name = "Contraversial", Color = "Red" } 
    Topic { Title = "Political Debate #1", Posted = 01/02/2008 } 
    Topic { Title = "iPhone to support SiliverLight!", Posted = 23/02/2009 } 
    Topic { Title = "Fed Chairman admits guilt for causing second Great Depression", Posted = 06/15/2010 } 
Tag { Name = "Politics", Color = "LightBlue" } 
    Topic { Title = "Political Debate #1", Posted = 01/02/2008 } 
    Topic { Title = "Fed Chairman admits guilt for causing second Great Depression", Posted = 06/15/2010 } 
Tag { Name = ".NET", Color = "LightGreen" } 
    Topic { Title = "iPhone to support SiliverLight!", Posted = 23/02/2009 } 

你可以假設數據的重複任何一塊是在是在內存中的單一實例和這些有幾個剛剛到同一對象引用指稱獨特。同樣,使用匿名類生成投影的答案也是合理的,因爲我認識到反轉後類的形狀可能稍微有些不同。

更新:我添加了下面的代碼設置示例數據。我正在玩LinqPad發佈的答案和我自己的一些想法。

var tags = new[] 
{ 
    new { Name = "Contraversial", Color = "Red" }, 
    new { Name = "Politics", Color = "LightBlue" }, 
    new { Name = ".NET", Color = "LightGreen" }, 
    new { Name = "BleedingEdge", Color = "LightBlue" } 

}; 

var topics = new[] 
{ 
    new 
    { 
     Title = "Political Debate #1", 
     Posted = DateTime.Parse("01/02/2008"), 
     Tags = (from t in tags where new []{"Contraversial", "Politics"}.Contains(t.Name) select t), 
    }, 
    new 
    { 
     Title = "iPhone to support SiliverLight!", 
     Posted = DateTime.Parse("02/23/2009"), 
     Tags = (from t in tags where new []{"BleedingEdge", "Contraversial", ".NET", }.Contains(t.Name) select t), 
    }, 
    new 
    { 
     Title = "Fed Chairman admits guilt for causing second Great Depression", 
     Posted = DateTime.Parse("06/15/2010"), 
     Tags = (from t in tags where new []{"Contraversial", "Politics"}.Contains(t.Name) select t), 
    }, 
}; 

回答

0

在LinqPad玩弄後一點,我想我可能已經找到了合適的解決方案。

下面是一個簡單的例子。

var topicsByTags = 
    from topic in topics 
    from tag in topic.Tags 
    group topic by tag; 

而爲了擺脫每個主題下的冗餘標籤集合,我們可以做到以下幾點。

var topicsByTags = 
    from topic in topics 
    from tag in topic.Tags 
    group new 
    { 
     Title = topic.Title, 
     Color = topic.Posted, 
    } by tag into g 
    select new 
    { 
     g.Key.Name, 
     g.Key.Color, 
     Topics = g, 
    }; 

UPDATE:下面是另一替代這需要在投影分組本身的優勢。上行是一個更簡潔的查詢,不利的一點是,即使不會使用該組,Key也會與該組保持一致。

var topicsByTags = 
    from topic in topics 
    from tag in topic.Tags 
    group new 
    { 
     Title = topic.Title, 
     Color = topic.Posted, 
    } by tag into g 
    select new 
    { 
     g.Key.Name, 
     g.Key.Color, 
     Topics = g, 
    }; 

我會延期接受我自己的答案,以便允許一些關於哪個解決方案解決了我提出的問題的爭論。

4

你在找什麼是樞軸。

Is it possible to Pivot data using LINQ?

This source包含C#代碼LINQ的透視擴展方法:

public static class LinqExtensions 
{ 

    public static Dictionary<TFirstKey, Dictionary<TSecondKey, TValue>> Pivot<TSource, TFirstKey, TSecondKey, TValue>(this IEnumerable<TSource> source, Func<TSource, TFirstKey> firstKeySelector, Func<TSource, TSecondKey> secondKeySelector, Func<IEnumerable<TSource>, TValue> aggregate) 
    { 
     var retVal = new Dictionary<TFirstKey, Dictionary<TSecondKey, TValue>>(); 

     var l = source.ToLookup(firstKeySelector); 
     foreach (var item in l) 
     { 
      var dict = new Dictionary<TSecondKey, TValue>(); 
      retVal.Add(item.Key, dict); 
      var subdict = item.ToLookup(secondKeySelector); 
      foreach (var subitem in subdict) 
      { 
       dict.Add(subitem.Key, aggregate(subitem)); 
      } 
     } 

     return retVal; 
    } 

} 
+0

一個數據透視表可能適用於我指定的特定反演案例,但我正在尋找的是將任意層次結構「重新組合」爲具有不同組織結構的方法。 – jpierson 2009-11-18 11:50:29

0
IDictionary<Topic, IList<Tag>> data; 
var n = data.SelectMany(x => x.Value.Select(y => new { Topic = x.Key, Tag = y })) 
    .GroupBy(x => x.Tag, x => x.Topic); 
+0

這可能適用於字典示例,但我正在尋找更多與自然對象層次結構一起工作的示例。請參閱我更新的帖子,其中包含一個示例設置。 – jpierson 2009-11-16 22:07:20