从CSV文件中获取重复数据

时间:2013-03-05 04:41:03

标签: c# csv

我有一个像这样的人类:

class Person
{
    string Id { get; set; }
    string FirstName { get; set; }
    string LastName { get; set; }
}

有一个CSV文件,其中包含人物数据,如

"123","ABC","DEF"
"456","GHI","JKL"
"123","MNO","PQR"
...

根据身份证明,某人是唯一的。

CSV的读取方式如下:

using (StreamReader sr = new StreamReader(inputFile))
{
    string[] arrCsvData;
    string strLine;

    while ((strLine = sr.ReadLine()) != null)
    {
        arrCsvData = strLine.Split(',');
        this.LoadPersonData(arrCsvData);
    }
 }

LoadPersonData中创建一个新的Person对象,并为其分配CSV值:

Person objPerson = new Person();
for (int i = 1; i <= arrCsvData.Length - 1; i++)
{
    // Assign person property values from arrCsvData
}

我有一个字典对象,其中键是ID,值是Person对象。

if(!this.PersonDataCollection.ContainsKey(personKey))
{
    this.PersonDataCollection.Add(objPerson);
}

这为我提供了CSV文件中所有唯一的Person对象。

我想创建一个基于CSV中Id的重复的Person对象列表。 因此列表DuplicatePersons将包含:

"123","ABC","DEF"
"123","MNO","PQR"

在其中。

简单的方法是首先将所有person对象读入列表,然后执行LINQ查询以将所有重复项都放在单独的列表中。这样我就可以创建一个额外的集合来获取重复项。

应该有一种比创建单独列表更好的方法。

任何指针?

4 个答案:

答案 0 :(得分:0)

为什么不在此时检查值是否已存在。

Person objPerson = new Person();
for (int i = 1; i <= arrCsvData.Length - 1; i++)
{
      // Assign person property values from arrCsvData
}

在此检查您的情况,并根据此处的重复值执行您想要的任何操作。

答案 1 :(得分:0)

无论你做什么......总会有一个单独的清单。这取决于你希望它们如何出现。

选项1 - 临时列表


每次查询现有字典时,都会返回内存中的结果。取决于您的数据集有多大......这可能不是您想要的。

选项2 - 静态列表


为什么不在此时维护自己的列表?:

if(!this.PersonDataCollection.ContainsKey(personKey))
{
    this.PersonDataCollection.Add(objPerson);
}
else
{
    // Create a new dictionary for the duplicates
    this.DuplicatePersonDataCollection.Add(objPerson);
}

答案 2 :(得分:0)

首先,我会使用LINQToCSV。解析CSV文件比仅按,拆分更复杂。您不需要编写任何代码,只需创建类,并在其上放置属性:

class Person
{
    [CsvColumn(Name = "ID", ...)]
    string Id { get; set; }
    [CsvColumn(Name = "First Name", ...)]
    string FirstName { get; set; }
    [CsvColumn(Name = "Last Name", ...)]
    string LastName { get; set; }
}

然后当您使用LINQToCSV阅读文件时,您会获得IEnumerable<Person> ...然后您可以执行以下操作:

IEnumerable<Person> people = ... //read here using LINQToCSV
var grouped = people.GroupBy(p => p.Id);

如果您在运行时知道唯一列,则可以执行以下操作:

string columnName = "Id";
persons.GroupBy(x => x.GetType().GetProperty(columnName).GetValue(x, null));

虽然你必须看到它对你的表现有多大影响。 另一种不需要反思的方式可能是:

Dictionary<string, Func<Person, object>> selectors = new Dictionary <string, Func<Person, object>>
            {
                {"Id", x => x.Id},
                {"FirstName", x => x.FirstName},
                {"LastName", x => x.LastName},
            };

string columnName = "Id";
var grouped = people.GroupBy(selectors[columnName]);

现在,使用您的方法......创建另一个字典有什么问题?

你可以拥有类似的东西:

//Here you will store the duplicated person
//Key: The person Id
//Value: The list of person sharing that same Id
Dictionary<string, IList<Person>> duplicatedPeople;


if(!this.PersonDataCollection.ContainsKey(personKey))
{
    this.PersonDataCollection.Add(objPerson);
}
else
{
    //Here we store all the people with this already existing ID
    IList<Person> duplicatedPeople;

    //If we already have this ID in the dictionary of repeated people
    if (this.duplicatedPeople.TryGetValue(personKey, out duplicatedPeople)) {
        //Just add this new person
        duplicatedPeople.Add(objPerson);
    }
    //If this is the 1st time we found a duplicated person with this ID
    else {
        //We add two persons to the list: this one, and the one from PersonDataCollection.
        duplicatedPeople = new List<Person> { this.PersonDataCollection[personKey], objPerson };
        //Add it to the dictionary
        this.duplicatedPeople.Add(personKey, duplicatedPeople);
    }
}

答案 3 :(得分:0)

为所有人创建一个列表,而不是使用LINQ查询它以获得结果:

即:

var persons = new List<Person>();
persons.Add(new Person { Id = "123", FirstName = "AAA", LastName = "XXX" });
persons.Add(new Person { Id = "123", FirstName = "BBB", LastName = "WWW" });
persons.Add(new Person { Id = "456", FirstName = "CCC", LastName = "XXX" });
persons.Add(new Person { Id = "456", FirstName = "DDD", LastName = "YYY" });
persons.Add(new Person { Id = "789", FirstName = "EEE", LastName = "ZZZ" });

var duplicateKeys = persons.GroupBy(p => p.Id).Select(g => new { g.Key, Count = g.Count() }).Where(x => x.Count > 1).ToList().Select(d => d.Key);
var duplicatePersons = persons.Where(p => duplicateKeys.Contains(p.Id)).ToList();
var unique = persons.GroupBy(p => p.Id).ToList();