(原创)扩展方法:给 IEnumerable<T> 扩展一个得到重复元素的方法

直接贴代码了,说明都在代码里。

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 下载:http://files.cnblogs.com/Music/enumerable_extension_iterative_Demo.rar

 

相关文章,希望你会喜欢:自定义 LINQ 中 Distinct 的 Compare,以及扩展 LINQ 的 Distinct,让它支持属性比较

谢谢浏览!

 

转载于:https://www.cnblogs.com/Music/archive/2012/02/26/enumerable-extension-iterative.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值