[英]faster way to iterate through and compare two lists of classes
我需要遍歷並比較 2 個類列表,然后比較 2 個並輸出匹配的記錄。 這需要幾個小時,我想不出加快這個過程的方法。 這些列表大約有 60 萬條記錄。 這是我的類代碼和用於迭代和比較的代碼。
class Person
{
string NPI;
string address;
string zip5;
string lname;
string lsk;
string state;
string fname;
string zipfull;
string seqNo;
public Person(string npi, string Address, string Zip5, string Lname, string LSK, string st, string Fname, string zipFull, string seqno)
{
this.NPI = npi;
this.address = Address;
this.zip5 = Zip5;
this.lname = Lname;
this.lsk = LSK;
this.state = st;
this.fname = Fname;
this.zipfull = zipFull;
this.seqNo = seqno;
}
public string getNPI()
{
return NPI;
}
public string getzip5()
{
return zip5;
}
public string getaddress()
{
return address;
}
public string Full()
{
string full = NPI + "," + address + "," + zip5 + "," + lname + "," + lsk + "," + state + "," + fname + "," + zipfull + "," + seqNo;
return full;
}
}
這是迭代的代碼。 fuzz.ratio 是我下載的模糊匹配 nuget 包,我知道這不是問題,因為我已經用它進行了速度測試,而且速度非常快
string inputfile = @"C:\Input_File_150k.csv";
string blacklist = @"C:\Blacklist1.csv";
List<Person> input = Readcsv(inputfile);
List<Person> BL = Readcsv(blacklist);
string outputtest = @"C:\outputtest.csv";
StringBuilder csvcontent = new StringBuilder();
int lengthinput = input.Count();
for(int i = 0; i <lengthinput; i++)
{
int lengthbl = BL.Count();
for(int x = 0; x < lengthbl; x++)
{
if(input[i].getzip5() == BL[x].getzip5())
{
if(input[i].getNPI() == BL[x].getNPI())
{
if(Fuzz.Ratio(input[i].getaddress(),BL[x].getaddress()) > 90)
{
csvcontent.AppendLine(input[i].Full());
}
}
}
}
}
File.AppendAllText(outputtest, csvcontent.ToString());
您可以遍歷每個列表一次以將所有值放入哈希映射中。 例如,您可以使用郵政編碼作為鍵,值是與該郵政編碼匹配的一組人。
然后你可以一次遍歷hashmap一條記錄,只需要將每個hashmap桶中的人相互比較即可。
除非你所有的人都在同一個郵政編碼中(如果是這樣,希望你的一個鍵可以用於這個),這應該比 N^2 比較快。 應該更接近 O(N),具體取決於每個桶中有多少人。
除了上面的評論( https://stackoverflow.com/a/60886352/5334191和使用字典),在你的循環中
int lengthinput = input.Count();
**int lengthbl = BL.Count();** //move out of the loops
for(int i = 0; i <lengthinput; i++)
{
**var inputi = input[i];** //move out of the inner loop
for(int x = 0; x < lengthbl; x++)
{
**var blx = BL[x];**
if(inputi.getzip5() == blx.getzip5())
{
if(inputi.getNPI() == blx.getNPI())
{
if(Fuzz.Ratio(inputi.getaddress(),blx.getaddress()) > 90)
{
csvcontent.AppendLine(inputi.Full());
}
}
}
}
}
我會定義實現 IEqualityComparer 接口。
這允許更清晰的代碼,並且還可以從集合上可用的一些 Linq 擴展方法中受益。
那些也支持諸如並行性之類的東西。
https://marcofranssen.nl/delegate-your-equality-comparisons/
嘗試從一個列表創建一個字典,在迭代另一個列表時用作查找。 這會將復雜性從多項式變為線性。
string inputfile = @"C:\Input_File_150k.csv";
string blacklist = @"C:\Blacklist1.csv";
List<Person> input = Readcsv(inputfile);
var blAddresses = Readcsv(blacklist).ToDictionary(
x => (Zip : x.getzip5(), NPI : x.getNPI()),
x => x.getaddress());
string outputtest = @"C:\outputtest.csv";
StringBuilder csvcontent = new StringBuilder();
int lengthinput = input.Count();
for(int i = 0; i <lengthinput; i++)
{
var zip = input[i].getzip5();
var npi = input[i].getNPI();
if(blAddresses.TryGetValue((zip,npi), out var blAddress)
{
if(Fuzz.Ratio(input[i].getaddress(),blAddress) > 90)
{
csvcontent.AppendLine(input[i].Full());
}
}
}
File.AppendAllText(outputtest, csvcontent.ToString());
具體來說,我創建了一個字典,該字典在 Zip 和 NPI 上鍵入並獲取所需的地址。 我正在使用一些 C# 7 的東西,比如值元組,但如果需要,可以將其更改為引用元組、匿名類或自定義類。
編輯
這是使這項工作的更改,就像您當前的代碼假設您有重復的 Zip/NPI 值一樣
string inputfile = @"C:\Input_File_150k.csv";
string blacklist = @"C:\Blacklist1.csv";
List<Person> input = Readcsv(inputfile);
var blAddresses = Readcsv(blacklist)
.GroupBy(x => (Zip : x.getzip5(), NPI : x.getNPI()))
.ToDictionary(
grp => grp.Key,
grp => grp.Select(y => y.getAddress()).ToList());
string outputtest = @"C:\outputtest.csv";
StringBuilder csvcontent = new StringBuilder();
int lengthinput = input.Count();
for(int i = 0; i <lengthinput; i++)
{
var zip = input[i].getzip5();
var npi = input[i].getNPI();
if(blAddresses.TryGetValue((zip,npi), out var blAddressList)
{
foreach(var blAddress in blAddressList)
{
if(Fuzz.Ratio(input[i].getaddress(),blAddress) > 90)
{
csvcontent.AppendLine(input[i].Full());
}
}
}
}
File.AppendAllText(outputtest, csvcontent.ToString());
或者,如果您只需要過濾掉黑名單中 NPI 為空白的任何內容以獲得唯一鍵,您可以改為執行此操作
var blAddresses = Readcsv(blacklist)
.Whree(x => x.getNPI().Length > 0)
.ToDictionary(
x => (Zip : x.getzip5(), NPI : x.getNPI()),
x => x.getaddress());
我認為這部分代碼可能很慢
字符串全 = NPI + "," + 地址 + "," + zip5 + "," + lname + "," + lsk + "," + state + "," + fname + "," + zipfull + "," + 序列號;
如果你執行csvcontent.Append
這些屬性和,
“手動”,而不是使用Full()
ps:它需要增加從外部讀取它的可能性,所以 public get / private set
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.