2017-03-31 87 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)) 
);