List<List<string>> lis1_比较 = new List<List<string>>()
{
new List<string>() { "0", "1", "2" },
new List<string>() { "0", "3", "4" }
};List<List<string>> lis2_比较 = new List<List<string>>()
{
new List<string>() { "0", "1" ,"2"},
new List<string>() { "4", "5" }
};List<List<string>> lis1_结果 = Enumerable.Intersect(lis1_比较, lis2_比较).ToList(); //取交集
Console.WriteLine(lis1_结果.Count);取两个集合的交集,为什么没有交集,不是有一个元素是相同的吗?
{
new List<string>() { "0", "1", "2" },
new List<string>() { "0", "3", "4" }
};List<List<string>> lis2_比较 = new List<List<string>>()
{
new List<string>() { "0", "1" ,"2"},
new List<string>() { "4", "5" }
};List<List<string>> lis1_结果 = Enumerable.Intersect(lis1_比较, lis2_比较).ToList(); //取交集
Console.WriteLine(lis1_结果.Count);取两个集合的交集,为什么没有交集,不是有一个元素是相同的吗?
解决方案 »
- ◆vs2010 winform 水晶报表 如何给未绑定字段UnboundString赋值◆
- 有一定C++基础,现在要学C#,该读哪些书?
- C#..JS..在线急等 限制窗口最大宽度 C#....
- 关于c# windows服务程序开发中"操作超时“的问题
- Singleton vs static class
- 弱问:如何将object强制转换成数组?
- 谁有多线程的文章,提供一下啊
- 如何在windows消息中传递字符串?
- 并非所有的代码路径都返回值
- visual c#中textBox怎么和数据绑定?记得VB里有这样的属性,而在这有没有?谢谢
- 怎么实现这个功能?
- 【求助】谁能看懂下面代码,然后用C#自动触发那个
//取交集
ArrayList al=new ArrayList();
ArrayList al1=new ArrayList();
ArrayList al2=new ArrayList();
int i;
for(i=0;i <10;i++)
{
al.Add(i);
}
for(i=5;i <20;i++)
{
al1.Add(i);
}
for(i=0;i <al.Count;i++)
{
if(al1.Contains(al[i]))
{
al2.Add(al[i]);
}
}
}
{
static void Main()
{
myeqc c = new myeqc();
List<List<string>> lis1_比较 = new List<List<string>>()
{
new List<string>() { "0", "1", "2" },
new List<string>() { "0", "3", "4" }
};
List<List<string>> lis2_比较 = new List<List<string>>()
{
new List<string>() { "0", "1" ,"2"},
new List<string>() { "4", "5" }
};
List<List<string>> lis1_结果 = Enumerable.Intersect(lis1_比较, lis2_比较,c).ToList();
Console.WriteLine(lis1_结果.Count);
Console.ReadKey();
}
}
class myeqc : IEqualityComparer<List<string>> //自定义相等比较器
{
public bool Equals(List<string> list1, List<string> list2)
{
int i = 0; //看看两个集合有多少个元素相同
foreach (string s in list1)
{
foreach (string s2 in list2)
{
if (s == s2)
i++;
}
}
if (i == list1.Count && i == list2.Count)
{
return true;
}
else
{
return false;
}
} public int GetHashCode(List<string> DF)
{
return DF.GetHashCode();
}
}那这样呢,我写了个自定义的比较器,但还是不行呢?
是的,你要比较的是两个List<string>,引用类型,只是他们包含的元素完全相同罢了,但运行时它们是两个完全独立的对象
public class MyComparer : IEqualityComparer<List<string>>
{
public bool Equals(List<string> x, List<string> y)
{
if (x.Count != y.Count) return false;
for (int i = 0, c = x.Count; i < c; i++)
{
if (!x[i].Equals(y[i]))
{
return false;
}
}
return true;
} public int GetHashCode(List<string> obj)
{
if (Object.ReferenceEquals(obj, null)) return 0;
int code = 0;
foreach (string item in obj)
{
code ^= item.GetHashCode();
}
return code;
}
} class Program
{
static void Main(string[] args)
{
List<List<string>> list1 = new List<List<string>>() {
new List<string>(){ "3", "1", "3" },
new List<string>(){ "1", "2" },
new List<string>(){ "0", "1", "2","4" }
}; List<List<string>> list2 = new List<List<string>>() {
new List<string>(){ "0", "1", "2","4" },
new List<string>(){ "0", "1", "3" },
new List<string>(){ "2", "1" }
}; List<List<string>> result = Enumerable.Intersect(list1, list2, new MyComparer()).ToList();
foreach (List<string> item in result)
{
Console.WriteLine("item:");
foreach (string sub in item)
{
Console.WriteLine(sub);
}
}
Console.Read();
}
}
result:
item:
0
1
2
4
{
return DF.GetHashCode();
}请问,GetHashCode方法这样写,为什么就不行呢?
public class CustomEqualityComparer : IEqualityComparer<List<string>>
{
public bool Equals(List<string> x, List<string> y)
{
//x==y==null
if (x == y)
return true;
if (x == null)
return false;
if (y == null)
return false;
if (x.Count != y.Count)
return false;
for (int i = 0, count = x.Count; i < count; i++)
{
if (x[i] != y[i])
return false;
}
return true;
//throw new NotImplementedException();
} public int GetHashCode(List<string> obj)
{
if (obj == null)
return 0; int hash = 17;
hash = (hash * 3) + obj.Count.GetHashCode();
foreach (string str in obj)
{
hash = (hash * 3) + str.GetHashCode();
}
return hash;
//throw new NotImplementedException();
}
}
请查看.NET类库的 Enumerable的Intersect方法 HashSet<T>的Add方法大概如下:public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
{
if (first == null)
{
throw Error.ArgumentNull("first");
}
if (second == null)
{
throw Error.ArgumentNull("second");
}
return IntersectIterator<TSource>(first, second, comparer);
} private static IEnumerable<TSource> IntersectIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
{
Set<TSource> iteratorVariable0 = new Set<TSource>(comparer);
foreach (TSource local in second)
{
iteratorVariable0.Add(local);
}
foreach (TSource iteratorVariable1 in first)
{
if (!iteratorVariable0.Remove(iteratorVariable1))
{
continue;
}
yield return iteratorVariable1;
}
}
如果iteratorVariable0.Add(local);这里添加不进去元素,你说你能取到什么交集Set<TSource> iteratorVariable0 = new Set<TSource>(comparer);这里以IEqualityComparer接口的一个实例变量来初始化一个Set集合变量关于Add方法,看这里:public bool Add(T item)
{
return this.AddIfNotPresent(item);
} private bool AddIfNotPresent(T value)
{
int freeList;
if (this.m_buckets == null)
{
this.Initialize(0);
}
int hashCode = this.InternalGetHashCode(value);
int index = hashCode % this.m_buckets.Length;
for (int i = this.m_buckets[hashCode % this.m_buckets.Length] - 1; i >= 0; i = this.m_slots[i].next)
{
if ((this.m_slots[i].hashCode == hashCode) && this.m_comparer.Equals(this.m_slots[i].value, value))
{
return false;
}
}
if (this.m_freeList >= 0)
{
freeList = this.m_freeList;
this.m_freeList = this.m_slots[freeList].next;
}
else
{
if (this.m_lastIndex == this.m_slots.Length)
{
this.IncreaseCapacity();
index = hashCode % this.m_buckets.Length;
}
freeList = this.m_lastIndex;
this.m_lastIndex++;
}
this.m_slots[freeList].hashCode = hashCode;
this.m_slots[freeList].value = value;
this.m_slots[freeList].next = this.m_buckets[index] - 1;
this.m_buckets[index] = freeList + 1;
this.m_count++;
this.m_version++;
return true;
}
private int InternalGetHashCode(T item)
{
if (item == null)
{
return 0;
}
return (this.m_comparer.GetHashCode(item) & 0x7fffffff);
}
int hashCode = this.InternalGetHashCode(value);
和
this.m_comparer.GetHashCode(item)这两句,可以发现集合列表的Add方法和该接口所实现的GetHashCode函数息息相关,其实这里,你应该就能明白,为什么该接口的一个实现类,他的GetHashCode能影响这个比较,因为其内部的集合Add元素,会先取该元素的hashcode
根据你Equal方法里面涉及到该引用类型的相关操作做一个哈希值统计,PS:11L的哈希值统计不好,请参考阿非的GetHashCode
GetHashCode 需要你自己提供的 就是override ,如果你不提供则会使用默认的 Object的GetHashCode 方法
运行时,会先调用GetHashCode获取每个字符串列表的散列值,如果它们不同,就不会调用Equals进行比较,只有散列值相同的情况下,才会用Equals进行比较。
下面的方法加上了一些输出语句,你可以看到方法被调用的过程:class myeqc : IEqualityComparer<List<string>> //自定义相等比较器
{
public bool Equals(List<string> list1, List<string> list2)
{
int i = 0; //看看两个集合有多少个元素相同
foreach (string s in list1)
{
foreach (string s2 in list2)
{
if (s == s2)
i++;
}
}
Console.WriteLine("正在比较:[{0}] 和 [{1}]", string.Join(",", list1.ToArray()), string.Join(",", list2.ToArray()));
Console.WriteLine("结果:{0}, 共{1}个元素,其中{2}个相同", i == list1.Count && i == list2.Count, Math.Max(list1.Count, list2.Count), i);
Console.WriteLine();
if (i == list1.Count && i == list2.Count)
{
return true;
}
else
{
return false;
}
} public int GetHashCode(List<string> DF)
{
int hash = 0;
Console.WriteLine("正在获取[{0}]的哈希值,返回{1}", string.Join(", ",DF.ToArray()), hash);
return hash;
}
}可以看到:如果返回的哈希值是0,一共执行4次比较,而改成:
int hash = DF.GetHashCode();
则因为所有的散列值都不同,所以一直比较也没执行,直接被认为没有相同的字符串列表。
如果改成:
int hash = DF.Aggregate(0, (h, s) => 32 * h + s.GetHashCode());
则一共只进行一次Equals比较。
传入EqualityComparer对象,这样解决方案比较好。