从对象数组中删除重复项

5

我有一个名为Customer的类,它有几个字符串属性,例如

firstName, lastName, email, etc.  

我从一个csv文件中读取客户信息,创建了该类的一个数组:

Customer[] customers  

我需要删除具有相同电子邮件地址的重复客户,只留下每个特定电子邮件地址的1个客户记录。 我已经使用了2个循环来完成此操作,但由于通常有50,000多个客户记录,因此需要近5分钟时间。 一旦我完成删除重复项,我需要将客户信息写入另一个csv文件(不需要帮助)。 如果我在循环中执行“Distinct”,那么我如何同时删除属于该特定客户的其他字符串变量?谢谢, Andrew

这个想法是每天/每周/每季度运行吗?任务的频率可能会决定解决方案的持久性。 - mjw
1
不使用新的相等比较器,自定义类型无法使用Distinct。请使用MoreLinq中的DistinctBy。顺便说一下,对于50k个项目,此操作不会花费太多时间,因为Distinct是O(n) - M.kazem Akhgary
1
我会使用 KeyedCollection(在 System.Collections.ObjectModel 中)。让电子邮件作为键,并在检查 Contains 后插入。这非常快... - Shnugo
可能相关/有帮助的链接:https://dev59.com/u3E85IYBdhLWcg3w8IQ4 - joranvar
这将每天运行。为了使用循环,我设置了外部循环来循环遍历客户数组,每次获取当前客户的电子邮件,然后设置一个内部循环来回检查所有客户的电子邮件地址,如果发现重复,我会在匹配的客户上设置一个布尔字段以标记删除。实际上,我不会删除客户条目,当我写入文件时,我首先检查这个布尔值是否为真,以确定是否应该写入。 - AWooster
显示剩余3条评论
2个回答

9

使用Linq,您可以通过GroupBy在O(n)时间内完成此操作(单层循环),

var uniquePersons = persons.GroupBy(p => p.Email)
                           .Select(grp => grp.First())
                           .ToArray();

更新

关于GroupByO(n)行为。

GroupByLinq中实现(Enumerable.cs)如下-

遍历IEnumerable只有一次来创建分组。使用提供的键(例如这里的“电子邮件”)的Hash来查找唯一的键,并将元素添加到对应的Grouping中的键中。

请参阅此GetGrouping代码。还有一些旧帖子供参考。

然后,Select显然是一个O(n)的代码,使得上面的代码总体复杂度为O(n)

更新2

处理null/empty值。

因此,如果存在Email的值为nullempty的实例,则简单的GroupBy将从nullempty中各取一个对象。

一种快速包含所有具有null/empty值的对象的方法是在运行时为这些对象使用一些唯一的键,例如

var tempEmailIndex = 0;
var uniqueNullAndEmpty = persons
                         .GroupBy(p => string.IsNullOrEmpty(p.Email) 
                                       ? (++tempEmailIndex).ToString() : p.Email)
                         .Select(grp => grp.First())
                         .ToArray();

1
@Shnugo - LINQ 不使用反射。 - Enigmativity
这个程序运行得非常好,但是出现了一个问题,它现在没有将任何内容写入到CSV文件中。我看到在删除重复项后,它返回了新的客户数组并且其中有数据,而我没有更改任何写入文件的代码... - AWooster
不好意思,创建新的客户数组时必须传入客户记录的数量。 - AWooster
@AWooster 看起来你已经解决了 CSV 创建的问题,很高兴知道它有所帮助 :) - Arghya C
1
@MikeNakis 请查看,我已经更新了答案,并附上了解释和参考资料。 - Arghya C
显示剩余6条评论

0

我会这样做:

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<string, Person> {
    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... 
        }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接