簡體   English   中英

使用StartsWith從一個列表更新另一個列表的項目的最快方法

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM