2017-03-16 20 views
3

我輸入可能看起來像這樣的:如何組只能用相同屬性後續項目使用LINQ

A 1 2 C,D 
A 2 3 C,E 
B 4 5 F 
A 6 7 
A 7 8 D 
A 9 10 E 

我這些信息存儲在我的模型類:

public class Item { 

public String Name {get;set;} 
public int Start {get;set;} 
public int End {get;set;} 
public List<string> Orders {get;set;} 

} 

我試圖用Linq合併所有後續項目,如果項目具有相同的名稱並生成具有組中第一個項目的起始值的新項目,組中最後一個項目的結束值和所有定單列表的聯合。然後,它應該是這樣的:

A 1 3 C,D,E 
B 4 5 F 
A 6 10 D, E 

我嘗試以下LINQ的聲明,然而,組中的所有作爲和燒烤在一起,獨立的是否存在之間的任何其他項目。我需要改變什麼?訂單列表的聯合也缺失。

var groups = items.GroupBy(i => i.Name).ToList(); 

foreach (var group in groups) 
{ 
    result.Add(new Item { 
    Start = group.First().Start, 
    End = group.Last().End, 
    Name = group.First().Name }); 
} 

回答

2

使用經典的循環這個:

var List<List<Item>> groups = new List<List<Item>>() 
var currentGroup = new List<Item> { items.First() }; 
int i = 0; 
foreach(var item in items.Skip(1)) 
{ 
    if(currentGroup.First().Name != item.Name) 
    { 
     groups.Add(currentGroup); 
     currentGroup = new List<Item> { item }; 
    } 
    else 
    { 
     currentGroup.Add(item); 
     if(i == items.Count - 2) 
      groups.Add(currentGroup); 
    } 
    i++; 
} 

現在你可以通過遍歷groups -list與您的代碼繼續。

+0

你的結果變量會成爲他的組變量的權利? –

+0

不應該是我== items.Count - 1? – RoflcoptrException

+0

@RoflcoptrException否,「-2」部分是由於我跳過了「items」列表中的第一項。此外,在我進行比較時,'i'具有previos迭代的值,因此在第一次迭代中'i'等於零,使得items.Count_2也爲零,對於只有兩個項目的集合。 – HimBromBeere

2

也許不是最好的或最快速的方式,但我覺得無聊:

int groupID = -1; 

var result = items.Select((item, index) => 
{ 
    if (index == 0 || items[index - 1].Name != item.Name) 
     ++groupID; 

    return new { group = groupID, item = item }; 
}).GroupBy(item => item.group).Select(group => 
{ 
    Item item = new Item(); 

    var first = group.First().item; 
    var last = group.Last().item; 

    item.Name = first.Name; 
    item.Start = first.Start; 
    item.End = last.End; 
    item.Orders = group.SelectMany(g => g.item.Orders).Distinct().ToList(); 

    return item; 
}); 

變量items應該是你的輸入集合像List<Item>。結果將被存儲在result。這是一個IEnumerable<Item>,但您可以根據需要添加.ToList().ToArray()將其轉換爲List<Item>Item[]

結果將包含新創建的項目。我故意這樣做不會搞亂輸入數據。

這裏的技巧是使用局部變量作爲組ID。如果它是第一個項目或最後一個項目具有不同的名稱,它會增加。然後,我們按組ID分組,其餘代碼將只創建該項目。 SelectMany方法將加入來自整個組的所有Orders值,然後Distinct將刪除所有重複項。

0

這不是Linq完成的。我只是玩了一些簡單的方法。但它給出了你想要的結果。

using System; 
using System.Collections.Generic; 

public class Item 
{ 
    public static List<Item> Database; 

    static Item() 
    { 
     Database = new List<Item>(); 
    } 

    public Item(string name, int start, int end, params string[] orders) 
    { 
     Name = name; 
     Start = start; 
     End = end; 
     Orders = new List<string>(); 
     foreach (string s in orders) 
      Orders.Add(s); 
     //putting newly created Item to database 
     Database.Add(this); 
    } 

    //overload for creating tmp Items in GroupThem(), could be done using optinional parameter 
    public Item(bool AddToDatabase, string name, int start, int end, params string[] orders) 
    { 
     Name = name; 
     Start = start; 
     End = end; 
     Orders = new List<string>(); 
     foreach (string s in orders) 
      Orders.Add(s); 
     if (AddToDatabase) Database.Add(this); 
    } 

    public string Name { get; set; } 
    public int Start { get; set; } 
    public int End { get; set; } 
    public List<string> Orders { get; set; } 

    public List<Item> GroupedItems() 
    { 
     List<Item> groupedItems = new List<Item>(); 
     Item previous = Database[0]; 
     Stack<Item> sameItems = new Stack<Item>(); 

     foreach (Item item in Database) 
     { 
      if (previous.Name == item.Name) 
      { 
       sameItems.Push(item); 
      } 
      else 
      { 
       groupedItems.Add(GroupThem(sameItems)); 
       previous = item; 
       sameItems.Push(item); 
      } 
     } 
     groupedItems.Add(GroupThem(sameItems)); 
     return groupedItems; 
    } 

    private Item GroupThem(Stack<Item> sameItems) 
    { 
     string newName = ""; 
     int newEnd = 0; 
     int newStart = int.MaxValue; 
     List<string> newOrders = new List<string>(); 
     Item tmp = null; 
     while (sameItems.Count > 0) 
     { 
      tmp = sameItems.Pop(); 
      if (tmp.Start < newStart) 
       newStart = tmp.Start; 
      if (tmp.End > newEnd) 
       newEnd = tmp.End; 
      foreach (string s in tmp.Orders) 
       if (!newOrders.Contains(s)) 
        newOrders.Add(s); 
      newName = tmp.Name; 
     } 
     return new Item(false, newName, newStart, newEnd, newOrders.ToArray()); 
    } 

    public override string ToString() 
    { 
     string tmp = ""; 
     foreach (string s in Orders) 
      tmp += " " + s; 
     return "Name = " + Name + ", Start = " + Start + ", End = " + End +", Orders = "+ tmp; 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 

     Item item1 = new Item("A", 1, 2, "C", "D"); 
     Item item2 = new Item("A", 2, 3, "C", "E"); 
     Item item3 = new Item("B", 4, 5, "F"); 
     Item item4 = new Item("A", 6, 7); 
     Item item5 = new Item("A", 7, 8, "D"); 
     Item item6 = new Item("A", 9, 10, "E"); 

     foreach (Item item in item1.GroupedItems()) 
     { 
      Console.WriteLine(item); 
     } 
    } 
}