寻求基于Linq优化Selection列表JOIN匹配算法的解决方案
Absolutely! The nested loop approach you're using has O(n*m) time complexity—which gets slow quickly as your lists grow—and it wastes cycles checking additional items even after a match is found (since your SQL tables enforce unique IDs and names). Let's refactor this with LINQ and dictionary lookups to get O(n+m) time complexity while preserving your exact matching logic.
Step 1: Define a Helper Method for Clean Name Matching
First, let's formalize the regex-based name cleaning logic you're using (I'll assume your RegexReplace method is a wrapper for Regex.Replace):
private string GetCleanSelectionName(string name) { // Remove parentheses containing numbers/decimals (e.g., "Item (1.2)" → "Item ") return Regex.Replace(name, @"\([\d.]+\)", string.Empty); }
Step 2: Preprocess Database Selections into Lookup Dictionaries
We'll build three dictionaries to enable O(1) lookups—this is the key to the performance gain. Since your SQL tables enforce unique IDs and names, most dictionaries will have one-to-one mappings. For cleaned names (which might collide), we'll take the first matching entry to match your original loop's behavior:
// Lookup by IdSelectionType (unique per your SQL index) var dbSelectionsById = mkDB.Selections.ToDictionary(sel => sel.IdSelectionType); // Lookup by original Name (unique per your SQL index) var dbSelectionsByName = mkDB.Selections.ToDictionary(sel => sel.Name); // Lookup by cleaned name (handle potential duplicates by taking the first match) var dbSelectionsByCleanName = mkDB.Selections .GroupBy(sel => GetCleanSelectionName(sel.Name)) .ToDictionary(group => group.Key, group => group.First());
Step 3: Match Templates to Database Entries Efficiently
Now we can iterate through each template selection and use the dictionaries to find matches in constant time, following your original priority order:
- 优先匹配
IdSelectionType(if the template selection has a non-null ID) - If no ID match, try matching the original
Name - If no name match, try matching the cleaned name (without numeric parentheses)
foreach (var selTPL in mkTPL.Selections) { SelectionPrints matchingDbSel = null; // Priority 1: Match by IdSelectionType if available if (selTPL.IdSelectionType != null && dbSelectionsById.TryGetValue(selTPL.IdSelectionType, out var idMatch)) { matchingDbSel = idMatch; } // Priority 2: Match by original Name else if (dbSelectionsByName.TryGetValue(selTPL.Name, out var nameMatch)) { matchingDbSel = nameMatch; } // Priority 3: Match by cleaned Name else { var cleanTplName = GetCleanSelectionName(selTPL.Name); dbSelectionsByCleanName.TryGetValue(cleanTplName, out matchingDbSel); } // Update the template value if a match was found if (matchingDbSel != null) { selTPL.OddOrResultValue = matchingDbSel.OddOrResultValue; } }
Why This Is Better
- Performance: Preprocessing takes O(m) time (where m is the size of
mkDB.Selections), and each template lookup is O(1). Total time complexity drops from O(n*m) to O(n+m)—a massive improvement for large lists. - No Redundant Checks: Unlike the nested loop, we stop searching as soon as we find a match.
- Preserves Your Logic: The matching priority and name-cleaning behavior are identical to your original
IsStessaSelezionemethod. - Maintainability: The code is more readable and separates the lookup preparation from the matching logic.
内容的提问来源于stack exchange,提问作者Revious

