(原创)扩展方法:给 IEnumerable<T> 扩展一个得到重复元素的方法
2012-02-26 22:04 音乐让我说 阅读(1396) 评论(5) 编辑 收藏 举报直接贴代码了,说明都在代码里。
using System;
using System.Collections.Generic;
using System.IO;
namespace ConAppTest
{
class Program
{
static void Main(string[] args)
{
// 测试1
int[] nums1 = new int[] { 1, 2, 3, 3, 5, 8, 3, 2, 9, 7, 7 };
Console.WriteLine("num1 中的重复元素:");
foreach (var item in nums1.Iterative())
{
Console.Write(item + "、");
}
Console.WriteLine(Environment.NewLine);
// 测试2
string[] words1 = new string[] { "Hello", "Bruce", "World", "Liu", "Hello", "Bruce", "Bruce" };
Console.WriteLine("words1 中的重复元素:");
foreach (var item in words1.Iterative())
{
Console.Write(item + "、");
}
Console.WriteLine(Environment.NewLine);
//File.AppendAllText(Path.Combine(Environment.CurrentDirectory, "guid.txt"), Guid.NewGuid().ToString());
// 测试3
Product product1 = new Product() { Id = Guid.NewGuid(), Name = "娃哈哈营养快线" };
Product product2 = new Product() { Id = new Guid("b8e5dd8a-4100-4f79-bf77-bf4e80185398"), Name = "健力宝" };
Product product3 = new Product() { Id = new Guid("b8e5dd8a-4100-4f79-bf77-bf4e80185398"), Name = "健力宝" };
Product product4 = product1;
Product product5 = new Product() { Id = Guid.NewGuid(), Name = "优乐美" };
Product product6 = product4;
Product product7 = product5;
Product product8 = new Product() { Id = Guid.NewGuid(), Name = "旺仔" };
Product product9 = new Product() { Id = Guid.NewGuid(), Name = "旺仔" };
Product product10 = new Product() { Id = new Guid("1442004b-b846-40ce-8647-2ffdeb6f0df1"), Name = "伊利金典纯牛奶" };
Product product11 = new Product() { Id = new Guid("1442004b-b846-40ce-8647-2ffdeb6f0df1"), Name = "蒙牛纯牛奶" };
Product[] products1 = new Product[]
{
product1,product2,product3,product4,product5,product6,product7,product8,product9,product10,product11
};
Console.WriteLine("products1 中的重复元素:");
foreach (var item in products1.Iterative())
{
Console.WriteLine("Id: " + item.Id + " , Name: " + item.Name);
}
Console.WriteLine(Environment.NewLine);
// 测试4
ProductCompare comparer = new ProductCompare();
Console.WriteLine("products1 中的重复元素(应用了比较器):");
foreach (var item in products1.Iterative(comparer))
{
Console.WriteLine("Id: " + item.Id + " , Name: " + item.Name);
}
Console.WriteLine(Environment.NewLine);
// 测试5
Console.WriteLine("products1 中的重复元素(自定义属性比较,比较 Name):");
foreach (var item in products1.Iterative(p => p.Name))
{
Console.WriteLine("Id: " + item.Id + " , Name: " + item.Name);
}
Console.WriteLine(Environment.NewLine);
// 测试6
Console.WriteLine("products1 中的重复元素(自定义属性比较,比较 Id):");
foreach (var item in products1.Iterative(p => p.Id))
{
Console.WriteLine("Id: " + item.Id + " , Name: " + item.Name);
}
Console.WriteLine(Environment.NewLine);
}
}
class Product
{
public Guid Id { get; set; }
public string Name { get; set; }
}
class ProductCompare : IEqualityComparer<Product>
{
public bool Equals(Product x, Product y)
{
return (x.Id == y.Id && x.Name == y.Name);
}
public int GetHashCode(Product obj)
{
// return obj.GetHashCode(); // GetHashCode()方法直接用obj.GetHashCode()的话,Distinct不能正常运行。
return obj.ToString().ToLower().GetHashCode();
}
}
}
EnumerableExtension.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace ConAppTest
{
public static class EnumerableExtension
{
/// <summary>
/// 得到重复元素,如果一个集合中有多个重复元素,只取第2个重复元素,比如 1,2,8,8,5,8,那么得到的结果将是索引为 3 的 8
/// </summary>
/// <typeparam name="TSource">可被枚举的集合</typeparam>
/// <param name="source"></param>
/// <returns></returns>
public static IEnumerable<TSource> Iterative<TSource>(this IEnumerable<TSource> source)
{
return Iterative(source, null);
}
/// <summary>
/// 得到重复元素,如果一个集合中有多个重复元素,只取第2个重复元素,比如 1,2,8,8,5,8,那么得到的结果将是索引为 3 的 8
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="source">可被枚举的集合</param>
/// <param name="comparer">比较器</param>
/// <returns></returns>
public static IEnumerable<TSource> Iterative<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
{
if(source == null)
{
throw new ArgumentNullException("source");
}
Set<TSource> iteratorSet = new Set<TSource>(comparer);
Set<TSource> returnIteratorSet = new Set<TSource>(comparer);
// 注意:这里的 Set 泛型类是 System.Linq 命名空间下的一个 internal 类,
// 可以把它反编译,复制到你的命名空间下,也可以用 HashSet<TSource> 来代替
// HashSet<TSource> iteratorSet = new HashSet<TSource>(comparer);
// HashSet<TSource> returnIteratorSet = new HashSet<TSource>(comparer);
foreach (TSource item in source)
{
if(!iteratorSet.Add(item) && returnIteratorSet.Add(item))
{
yield return item;
}
}
}
/// <summary>
/// 得到重复元素,如果一个集合中有多个重复元素,只取第2个重复元素,比如 1,2,8,8,5,8,那么得到的结果将是索引为 3 的 8
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TKey"></typeparam>
/// <param name="source">可被枚举的集合</param>
/// <param name="keySelector">需要比较的属性,多个属性可以实例化一个匿名类,比如:d => new { d.Id, d.Name } </param>
/// <returns></returns>
public static IEnumerable<TSource> Iterative<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
Set<TKey> iteratorSet = new Set<TKey>();
Set<TKey> returnIteratorSet = new Set<TKey>();
// 注意:这里的 Set 泛型类是 System.Linq 命名空间下的一个 internal 类,
// 可以把它反编译,复制到你的命名空间下,也可以用 HashSet<TSource> 来代替
// HashSet<TKey> iteratorSet = new HashSet<TKey>();
// HashSet<TKey> returnIteratorSet = new HashSet<TKey>();
foreach (TSource item in source)
{
var elementValue = keySelector(item);
if (!iteratorSet.Add(elementValue) && returnIteratorSet.Add(elementValue))
{
yield return item;
}
}
}
}
internal class Set<TElement>
{
// Fields
private int[] buckets;
private IEqualityComparer<TElement> comparer;
private int count;
private int freeList;
private Slot<TElement>[] slots;
// Methods
public Set()
: this(null)
{
}
public Set(IEqualityComparer<TElement> comparer)
{
if (comparer == null) comparer = EqualityComparer<TElement>.Default;
this.comparer = comparer;
this.buckets = new int[7];
this.slots = new Slot<TElement>[7];
this.freeList = -1;
}
public bool Add(TElement value)
{
return !this.Find(value, true);
}
public bool Contains(TElement value)
{
return this.Find(value, false);
}
private bool Find(TElement value, bool add)
{
int hashCode = this.InternalGetHashCode(value);
for (int i = this.buckets[hashCode % this.buckets.Length] - 1; i >= 0; i = this.slots[i].next)
{
if (this.slots[i].hashCode == hashCode && this.comparer.Equals(this.slots[i].value, value)) return true;
}
if (add)
{
int freeList;
if (this.freeList >= 0)
{
freeList = this.freeList;
this.freeList = this.slots[freeList].next;
}
else
{
if (this.count == this.slots.Length) this.Resize();
freeList = this.count;
this.count++;
}
int index = hashCode % this.buckets.Length;
this.slots[freeList].hashCode = hashCode;
this.slots[freeList].value = value;
this.slots[freeList].next = this.buckets[index] - 1;
this.buckets[index] = freeList + 1;
}
return false;
}
internal int InternalGetHashCode(TElement value)
{
if (value != null) return (this.comparer.GetHashCode(value) & 0x7fffffff);
return 0;
}
public bool Remove(TElement value)
{
int hashCode = this.InternalGetHashCode(value);
int index = hashCode % this.buckets.Length;
int num3 = -1;
for (int i = this.buckets[index] - 1; i >= 0; i = this.slots[i].next)
{
if (this.slots[i].hashCode == hashCode && this.comparer.Equals(this.slots[i].value, value))
{
if (num3 < 0)
this.buckets[index] = this.slots[i].next + 1;
else
this.slots[num3].next = this.slots[i].next;
this.slots[i].hashCode = -1;
this.slots[i].value = default(TElement);
this.slots[i].next = this.freeList;
this.freeList = i;
return true;
}
num3 = i;
}
return false;
}
private void Resize()
{
int num = this.count * 2 + 1;
int[] numArray = new int[num];
Slot<TElement>[] destinationArray = new Slot<TElement>[num];
Array.Copy(this.slots, 0, destinationArray, 0, this.count);
for (int i = 0; i < this.count; i++)
{
int index = destinationArray[i].hashCode % num;
destinationArray[i].next = numArray[index] - 1;
numArray[index] = i + 1;
}
this.buckets = numArray;
this.slots = destinationArray;
}
// Nested Types
[StructLayout(LayoutKind.Sequential)]
internal struct Slot<TElement>
{
internal int hashCode;
internal TElement value;
internal int next;
}
}
}
运行截图:
Demo 下载:https://files.cnblogs.com/Music/enumerable_extension_iterative_Demo.rar
相关文章,希望你会喜欢:自定义 LINQ 中 Distinct 的 Compare,以及扩展 LINQ 的 Distinct,让它支持属性比较
谢谢浏览!
作者:音乐让我说(音乐让我说 - 博客园)
出处:http://music.cnblogs.com/
文章版权归本人所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。