2017-03-31 77 views
0

底線是我想要一個linq語句返回與下面的代碼相同的列表。從列表中篩選列表

我覺得這是可能的,我覺得我非常接近,然後才放棄,只是用更多的代碼說明了我想要的東西。

雖然我會喜歡和欣賞任何能證明我期待未來實現的東西,並取代我擁有的東西。

public ObservableCollection<VarItem> IndexChannels 
{ 
    get 
    { 
     ObservableCollection<VarItem> filtered = new ObservableCollection<VarItem>(); 

     filtered.Add(indexChannels.First());//add Disabled no matter what 

     //add the cur channels selected index if it isn't already disabled 
     if (!filtered.Contains(indexChannels.FirstOrDefault(i => i == CurChannel.IndexChannel))) 
     { 
      filtered.Add(indexChannels.FirstOrDefault(i => i == CurChannel.IndexChannel)); 
     } 

     foreach (PdioChannelModel ch in channels) 
     { 
      //if the channels mode isn't q-decode or quad index add its Number as an index 
      if (ch.Mode.Value != "Q-Decode" && ch.Mode.Value != "Quad Index") 
      { 
       filtered.Add(indexChannels.FirstOrDefault(i => i.ID == ch.Number)); 
      } 
     } 
     return filtered; 
    } 
} 

VarItem

的基本結構

公共類VarItem { 公衆詮釋ID {獲得;私人設置; } public string Value {get;私人設置; } public Dictionary MetaData {get;私人設置; }

public VarItem(int id, string value) 
    { 
    this.ID = id; 
    this.Value = value; 
    MetaData = new Dictionary<string, string>(); 
    } 

例如主列表包含VarItems:

-1, 「禁用」

1, 「通道1」

2中, 「通道2」

3, 「頻道3」

過濾列表應始終包含VarItem(-1, Disabled)。它也應該包含VarItem其中ID比賽CurChannel.IndexChannel,最後它含有前人的精力任何VarItem S其中的ID匹配任何PdioChannelModel.Number其中PdioChannelModel.Mode.Value != "Q-Decode" or "Quad Index"

如果我錯過了所需要的任何細節讓我知道。如果我讓你感到困惑,寫信給你或者需要澄清,請讓我知道。

+0

你們是不是因爲,作爲一個命令實際上它有效地做,而你很可能寫LINQ的單位,以取代所有的代碼或僅僅指剛在foreach位三種不同的東西(默認,當前,過濾)可能意味着將這些東西分開的可讀性更高。該foreach可能很容易更改爲'filtered.AddRange'和Where後跟Select,如果這就是你想要的,但我會傾向於「如果它沒有壞,不修復它」。雖然當然作爲一個學習練習下次它仍然有用... :) – Chris

+0

一些問題。 '渠道'從哪裏來?它是否與'indexChannels'類型相同? 「IndexChannels」(首字母I)是否是一個錯字?並保證'indexChannels.First()'總是「禁用」項目?我認爲這可以通過篩選和排序來實現。 –

回答

0

一種方法是生成要添加的項目列表並將其傳遞給構造函數。

我們確實知道我們想要indexChannels中的第一個項目,並且當前頻道選擇了索引(如果它存在的話),因此這部分非常簡單 - 只需new List<VarItem>即可。

接下來,您希望添加所有ID與匹配其模式不是Q解碼或四叉索引的通道的編號相匹配的索引通道。因此,我會用Union加入第一個列表。

最後,由於FirstOrDefault回報default(VarItem)爲默認值,我們就可以去掉那些在最後,我們可以扔在那裏,以及一個Distinct,以確保我們不會有重複:

get 
{ 
    return new ObservableCollection<VarItem>((
     new List<VarItem> 
     { 
      indexChannels.First(), 
      indexChannels.FirstOrDefault(i => i == CurChannel.IndexChannel) 
     }) 
     .Union(channels 
      .Where(ch => ch.Mode.Value != "Q-Decode" && 
         ch.Mode.Value != "Quad Index") 
      .Select(ch => indexChannels.FirstOrDefault(i => i.ID == ch.Number))) 
     .Where(varItem => varItem != default(VarItem)) 
     .Distinct()); 
} 

只是爲了記錄,我絕不會在生產代碼中這樣做。在這個聲明中的任何失敗將是一個巨大的調試痛苦。通常每行執行一條語句對其他人來說更容易閱讀,並且在一條線路出現故障時更容易進行調試。

0

您是否在意如果將值添加到您的ObservableCollection?如果要排除null值,則FirstOrDefault不適合在您的foreach中使用。另一方面,如果您肯定知道每個頻道Number財產將存在至少一次indexChannels,那麼只需使用First。這樣,如果你的假設是錯誤的(和Number不匹配任何ID),那麼First將拋出一個異常,這可能是你想要的,而不是稍後的NullReferenceException,這將很難調試。另外,如果您確定每個頻道Number屬性只會在indexChannels中存在一次,那麼請使用Single,這樣您在違反此第二個假設時會收到異常。再次,比以後一些意外的行爲更容易調試。

下面是一個例子的解決方案:

return new ObservableCollection<VarItem>(
    indexChannels 
    .Take(1) 
    .Union(indexChannels.Where(i => i == CurChannel.IndexChannel).Take(1)) 
    .Union(channels 
     .Where(c => c.Mode.Value != "Q-Decode" && 
        c.Mode.Value != "Quad Index") 
     // The following line could be turned into 
     // .Select(c => indexChannels.First(i => i.ID == c.Number)) 
     // OR 
     // .Select(c => indexChannels.Single(i => i.ID == c.Number)) 
     // OR 
     // .SelectMany(c => indexChannels.Where(i => i.ID == c.Number)) 
     // depending on how many channels in indexChannels 
     // are expected to match each Number property. 
     .Select(c => indexChannels.FirstOrDefault(i => i.ID == c.Number)) 
);