从对象数组中删除重复项
我有一个名为Customer
的类,它有几个字符串属性
firstName, lastName, email, etc.
我从csv
文件中读取客户信息,该文件创建了该类的数组:
Customer[] customers
我需要删除具有相同电子邮件地址的重复客户,每个特定电子邮件地址只留下1个客户记录。
我使用2个循环完成了这项工作,但由于通常有50,000多个客户记录,因此需要将近5分钟。 完成删除重复项后,我需要将客户信息写入另一个csv文件(此处无需帮助)。
如果我在循环中做了一个Distinct
,我如何删除该特定客户的类的一部分的其他字符串变量?
谢谢,安德鲁
使用Linq
,您可以使用GroupBy
在O(n)时间(单级循环)中执行此操作
var uniquePersons = persons.GroupBy(p => p.Email) .Select(grp => grp.First()) .ToArray();
更新
关于GroupBy
O(n)
行为。
GroupBy
在Linq
( Enumerable.cs
)中实现,因为 –
IEnumerable
仅迭代一次以创建分组。 提供的密钥的Hash
(例如,此处为“电子邮件”)用于查找唯一密钥,并且元素被添加到与密钥对应的Grouping
。
请参阅此GetGrouping代码。 还有一些旧post可供参考。
- GroupBy操作的渐近复杂性是什么?
- LINQ方法的运行时复杂性(Big-O)有什么保证?
然后Select
显然是一个O(n)代码,整体上面的代码为O(n)
。
更新2
处理empty
/ null
值。
因此,如果存在Email
值为null
或为empty
实例,则简单的GroupBy
将仅从null
取出其中一个对象并empty
每个对象。
将所有具有null
/ empty
值的对象包含在内的一种快速方法是在运行时为这些对象使用一些唯一键,例如
var tempEmailIndex = 0; var uniqueNullAndEmpty = persons .GroupBy(p => string.IsNullOrEmpty(p.Email) ? (++tempEmailIndex).ToString() : p.Email) .Select(grp => grp.First()) .ToArray();
我这样做:
public class Person { public Person(string eMail, string Name) { this.eMail = eMail; this.Name = Name; } public string eMail { get; set; } public string Name { get; set; } } public class eMailKeyedCollection : System.Collections.ObjectModel.KeyedCollection { protected override string GetKeyForItem(Person item) { return item.eMail; } } public void testIt() { var testArr = new Person[5]; testArr[0] = new Person("Jon@Mullen.com", "Jon Mullen"); testArr[1] = new Person("Jane@Cullen.com", "Jane Cullen"); testArr[2] = new Person("Jon@Cullen.com", "Jon Cullen"); testArr[3] = new Person("John@Mullen.com", "John Mullen"); testArr[4] = new Person("Jon@Mullen.com", "Test Other"); //same eMail as index 0... var targetList = new eMailKeyedCollection(); foreach (var p in testArr) { if (!targetList.Contains(p.eMail)) targetList.Add(p); } }
如果在集合中找到该项,您可以使用以下方法轻松选择(并最终修改)它:
if (!targetList.Contains(p.eMail)) targetList.Add(p); else { var currentPerson=targetList[p.eMail]; //modify Name, Address whatever... }