[英]Fastest way of updating items of one list from another using StartsWith
我有一種情況,我需要根據另一個列表中的數據來更新一些項目。 我已經在這里經歷了各種問題,但沒有一個幫助。
情境
listA:總數約88000
public class CDRs
{
public string cld { get; set; }
public string prefix2 { get; set; }
public string country { get; set; }
public string city { get; set; }
}
listB:總數:3000。
public class RatesVM
{
public string prefix { get; set; }
public string Country { get; set; }
public string City { get; set; }
}
現在,在數組listB可以有場listA的多場比賽是CLD
例如 listA.cld =“ 8801123232”; 我得到的來自ListB的匹配前綴是
880 BGD Proper
8801 BGD Mobile
88011 BGD Dhaka Mobile
88017 BGD Dhaka Mobile
88018 BGD Dhaka Mobile
88019 BGD Dhaka Mobile
現在我想在這種情況下最接近的匹配是
88011 BGD Dhaka Mobile
方法我現在正在關注。
foreach (var x in listA)
{
var tempObj = listB.FirstOrDefault(y => x.cld.StartsWith(y.prefix));
if (tempObj != null)
{
x.prefix2 = tempObj.prefix;
x.country = tempObj.Country;
x.city = tempObj.City;
}
else
{
x.prefix2 = "InBound";
x.country = "Unknown";
x.city = "Unknown";
}
}
它工作正常,但要花費很多時間。 在這種情況下, 大約需要2-3分鍾 。
在極少數情況下,ListA將擁有大約一百萬條記錄。 我擔心這將永遠。
提前謝謝了
我建議下面的代碼。 關鍵的區別是使用orderedListB
來確保您獲得最具體的匹配(即首先從最長的前綴開始),以及用於緩存結果的Dictionary
。 *
Dictionary<string, RatesVM> cache = new Dictionary<string, RatesVM>();
var orderedListB = listB.OrderByDescending(z => z.prefix.Length).ToList();
foreach (var x in listA)
{
RatesVM cached;
cache.TryGetValue(x.cld, out cached);
var tempObj = cached ?? orderedListB.FirstOrDefault(z => x.cld.StartsWith(z.prefix));
if (tempObj != null)
{
if (cached == null)
{
cache.Add(x.cld, tempObj);
}
x.prefix2 = tempObj.prefix;
x.country = tempObj.Country;
x.city = tempObj.City;
}
else
{
x.prefix2 = "InBound";
x.country = "Unknown";
x.city = "Unknown";
}
}
您可能還需要考慮使用Parallel.ForEach
而不是僅使用foreach。
您的問題很難解決,因為您需要“最接近的”解決方案,而不是任何解決方案。 這將迫使你在遍歷每個記錄listB
,在每個元素listA
。
由於您需要對listA
每個元素的答案,因此您必須檢查其中的每個元素。
但是,您可以通過創建樹結構來預處理listB
。 您為B中所有字符串的每個不同的第一個數字創建一個節點。然后,該節點將成為listB
中以該數字開頭的所有記錄的父級。 該節點下面的節點將保留字符串中的第二個數字,依此類推。
向前走,使您直觀地了解這種樹的外觀:
現在,如果您在listB
搜索,則不必遍歷整個listB
而只需遍歷該列表,這將使每次迭代的時間從O(n)
增加到O(log n)
。
您將把listA
中的記錄的第一個字母與樹進行比較,然后遍歷該分支(立即刪除大量您可能需要比較的記錄,從而提高性能)。 然后比較第二個字母,以此類推,直到在樹中找不到更多字母為止。 當您停止時,您在listB
找到了最長的匹配記錄, listB
保證了“最接近”的匹配,而FirstOrDefault(\\x -> x.StartsWith())
根本不匹配! (它只找到第一個匹配項,幾乎總是第一個字母!)。
你只需要一次在所有搜索創建此樹listA
,如果有變化中的listB
您可以輕松地更新樹為好。
如果您是在具有多個內核的一台像樣的機器上運行此程序,則還可以並行執行此搜索。 這將增加正在編寫的程序的復雜性,因為您需要管理listA
中記錄的哪些線程搜索,盡管這將大大提高性能,並大大減少所需的時間。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.