linq - 从n个列表中返回常用项

时间:2014-02-15 12:08:48

标签: c# linq

我正在为我们的Intranet应用程序编写一个简单的搜索页面。当用户搜索n个单词时,我创建了n个命中列表,然后只想返回所有列表共有的结果。

我有一些使用List<int>的工作因此:

var list1 = new List<int> {1,2,3,4,5,8,10};
var list2 = new List<int> {3,5,6,9,10,11};
var list3 = new List<int> {3,4,5,10};

var listOfLists = new List<List<int>>{list1,list2,list3};

var results = listOfLists.Aggregate((prevList, nextList) => prevList
                 .Intersect(nextList)
                 .ToList()); 

results.Dump(); //correctly returns 3,5,10, which are common to all lists

但是,如果我在我的SearchResults类中尝试此操作,则无法获得任何结果。这是代码:

//results from first search word "howard"
List<SearchResult> list1 = new List<SearchResult>();
list1.Add(new SearchResult ("a.html","howard kent"));
list1.Add(new SearchResult ("b.html","howard shaw")); //the common item
list1.Add(new SearchResult ("c.html","howard smith"));
list1.Add(new SearchResult ("d.html","howard moore"));

//results from second search word "shaw"
List<SearchResult> list2 = new List<SearchResult>();
list2.Add(new SearchResult ("e.html","jon shaw"));
list2.Add(new SearchResult ("b.html","howard shaw")); //the common item
list2.Add(new SearchResult ("f.html","chris shaw"));

//could be n further lists...

//make a list of lists
List<List<SearchResult>> searchLists = new List<List<SearchResult>>();
searchLists.Add(list1);
searchLists.Add(list2);

//find results that are common to all lists.
//Doesn't work - returns nil items, should return 1
var results = searchLists
             .Aggregate((prevList, nextList) => prevList
             .Intersect(nextList)
             .ToList()); 

results.Dump();

}

class SearchResult
{
    public string Url{get;set;}
    public string SearchText { get; set; }

//constructor
public SearchResult(string url,string searchText)
{
    Url = url;
 SearchText = searchText;
}

如何更改查询以返回我想要的结果?

2 个答案:

答案 0 :(得分:3)

这是因为SearchResult个对象不是相同的对象,尽管它们具有相同的数据。您可以通过实现IEquatable<T>接口来解决此问题。 http://msdn.microsoft.com/en-us/library/ms131187(v=vs.110).aspx

public class SearchResult : IEquatable<SearchResult>
{
    public string Url{get;set;}
    public string SearchText { get; set; }
    public bool Equals(SearchResult other)
    {
        if (other == null)
            return false;
        return string.Concat(this.Url, this.SearchText).Equals(string.Concat(other.Url, other.SearchText), StringComparison.OrdinalIgnoreCase);
    }
}

另一种解决方案是实现IEqualityComparer<T>并将其传递给Enumerable.Intersect方法。

答案 1 :(得分:1)

您可以使用Enumberable.Intersect获取常用项目。但在你的情况下,你正在比较两个对象。因此,您需要实现IEqualityComparer接口并创建自己的比较器类。

我假设你的SearchResult类是这样的

public class SearchResult
    {
        public SearchResult(string first, string second)
        {
            First = first;
            Second = second;
        }

        public string First { get; set; }
        public string Second { get; set; }

    }

现在是IEqualityComparer接口实现。

 public class MyCompare : IEqualityComparer<SearchResult>
    {
        public bool Equals(SearchResult x, SearchResult y)
        {
            return (x.First == y.First) && ((x.Second == y.Second));
        }


        public int GetHashCode(SearchResult obj)
        {
            unchecked
            {
                int hash = 17;
                hash = hash * 23 + obj.First.GetHashCode();
                hash = hash * 23 + obj.Second.GetHashCode();
                return hash;
            }
        }
}

重要的一点是GetHashCode我们需要将两个属性合并而不是一个属性。如果我们比较单一属性那么就像这样简单

return obj.A.GetHashCode();

但是我们在这里比较多个属性。所以我们需要改变它的实现。感谢@Tim到他们的post

现在,您可以使用Intersect方法获取此类常用项

var common = list1.Intersect<SearchResult>(list2,new MyCompare()).ToList();