我有一个像这样的人类:
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查询以将所有重复项都放在单独的列表中。这样我就可以创建一个额外的集合来获取重复项。
应该有一种比创建单独列表更好的方法。
任何指针?
答案 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();