从列表中过滤列表

时间:2017-03-31 20:42:43

标签: c# linq filter

底线是我想要一个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    {       public int ID {get;私人集; }       public string Value {get;私人集; }       公共字典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)。它还应包含VarItemID匹配的CurChannel.IndexChannel,最后它应包含ID与任何VarItem匹配的PdioChannelModel.Number PdioChannelModel.Mode.Value != "Q-Decode" or "Quad Index" @media screen and (max-width: 767px) { _::-webkit-full-page-media, _:future, :root .safari_only { padding: 10px; //or any property you need } } }

如果我错过任何需要的细节,请告诉我。如果我困惑你,写了很多或需要澄清,也请告诉我。

2 个答案:

答案 0 :(得分:0)

一种方法是生成要添加的项目列表并将其传递给构造函数。

我们肯定知道我们想要indexChannels中的第一项,并且当前频道选择索引(如果它在那里),因此该部分非常简单 - 只需new List<VarItem>

接下来,您要添加所有索引通道,这些通道的ID与模式不是Q-Decode或Quad Index的通道的编号相匹配。因此,为此,我使用Union将其与第一个列表连接起来。

最后,由于FirstOrDefault返回default(VarItem)作为默认值,我们可以在最后删除它们,我们也可以在其中放置Distinct以确保我们不会#39; t有重复:

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());
}

仅仅为了记录,我绝不会在生产代码中这样做。调试中的任何失败都将是一个巨大的痛苦。通常,每行一行语句更易于其他人阅读,并且当一行失败时更容易调试。

答案 1 :(得分:0)

您是否关心是否在null添加了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))
);