Linq选择包含的位置

时间:2014-08-12 07:53:30

标签: c# linq

我有2个对象(尝试使其工作有点像SO)与many to many关系,我想基于另一个过滤它们的一个集合。这是我的目标:

public class Code
{
    public int CodeId { get; set; }
    public string CodeName { get; set; }
    public string CodeData { get; set; }

    public virtual ICollection<Tag> Tags { get; set; }
}

public class Tag
{
    public int TagId { get; set; }
    public string Name { get; set; }
    public string Comments { get; set; }

    public virtual ICollection<Code> Codes { get; set; }
}

因此,如果我想要过滤Tags的集合,我想要返回Codes的集合,其tags至少包含一个所选标签,但是Tag中不存在选定Tags中的Code example
我尝试使用Linq,但最终得到了这个非linq解决方案:

public IEnumerable<Code> GetCodes()
    {
        //A collection to filter upon
        var SelectedTags = new List<Tag>();

        //the collction to return
        var FoundCodes = new List<Code>();

        foreach (Code code in GetAllCodes())
        {
            foreach (var tags in code.Tags)
            {
                if (SelectedTags.Contains(tags))
                {
                    if (!FoundCodes.Contains(code))
                    {
                        FoundCodes.Add(code);
                    }
                    continue;
                }
            }
            foreach (var selectedTags in SelectedTags)
            {
                if (!code.Tags.Contains(selectedTags))
                {
                    FoundCodes.Remove(code);
                }
            }
        }

        return FoundCodes;
    }

所以我的问题是我如何使用Linq

3 个答案:

答案 0 :(得分:2)

嗯,怎么样。

var foundCodes = GetAllCodes()
                   .Where(code => code.Tags.All(t => SelectedTags.Contains(t)))
                   .Distinct()
                   .ToList();

如果GetAllCodes()返回不同的结果,您可以省略Distinct来电。


继续@ Nuffin的评论

你可以试试,

SelectedTags = SelectedTags.OrderBy(t => t).ToList();

var foundCodes = GetAllCodes()
                   .Where(code =>
                       code.Tags
                           .OrderBy(t => t)
                           .SequenceEqual(SelectTags))
                   .Distinct()
                   .ToList();

但是,我怀疑您的查询提供程序无法将SequenceEqual转换为语句。

在这种情况下,请使用@ Nuffin的答案。

答案 1 :(得分:2)

这个简单的查询应该可以解决问题(找到所有选定标签的代码,而不是其他标签):( 请注意,虽然这段代码完全模仿了OP的实现行为,但这并不是理想的结果。下面是固定版本

public IEnumerable<Code> GetCodes()
{
    var SelectedTags = new List<Tag>(); /* fill this however */
    return from code in GetAllCodes() /* get all codes*/
           where SelectedTags.All(code.Tags.Contains) /* filter out codes with nonmatching tags */
           where code.Tags.All(SelectedTags.Contains) /* filter out codes with missing tags*/
           select code; /* return the remaining codes */
}

请注意,根据不同标签的数量,这可能会很慢,而不使用针对搜索进行优化的集合(尽管仍然比您的解决方案快一点)。

编辑:要获得图片上显示的结果(获取所有选定代码的所有代码,无论代码中包含其他代码),只需省略第二个where子句:

public IEnumerable<Code> GetCodes()
{
    var SelectedTags = new List<Tag>(); /* fill this however */
    return from code in GetAllCodes() /* get all codes*/
           where SelectedTags.All(code.Tags.Contains) /* filter out codes with nonmatching tags */
           select code; /* return the remaining codes */
}

答案 2 :(得分:0)

也许你可以这样缩短:

public IEnumerable<Code> GetCodes()
{
  //A collection to filter upon
  var SelectedTags = new List<Tag>();

  //the collction to return
  var FoundCodes = new List<Code>();

  foreach (var code in GetAllCodes())
  {
    foreach (var tags in code.Tags.Where(tags => SelectedTags.Contains(tags)))
    {
      if (!FoundCodes.Contains(code))
      {
        FoundCodes.Add(code);
      }
      continue;
    }
    foreach (var selectedTags in SelectedTags.Where(selectedTags => !code.Tags.Contains(selectedTags)))
    {
      FoundCodes.Remove(code);
    }
  }

  return FoundCodes;
}

也许你可以发帖GetAllCodes() ...问题是因为foreach中的循环我不知道如何将它缩短为linq方法链。