如何基于输入值从Python字典列表中匹配对应名称并优化代码的性能与可读性?
Optimizing Size-to-Name Mapping with a Class-Based Solution
Great question! Your existing code gets the job done, but we can refactor it into a clean, class-based implementation that boosts readability, maintainability, and lookup performance—perfect if you’re checking values frequently.
The Refactored Solution
Here’s an improved version that avoids anti-patterns like using try-except for control flow, preprocesses data once, and uses efficient lookup logic:
import random import bisect class SizeToNameMapper: def __init__(self, size_entries): # Extract the "any" fallback entry (matches your original logic as a last resort) self.fallback_entry = next( (entry for entry in size_entries if entry["min_size"] == "any" or entry["max_size"] == "any"), None ) # Process interval entries: filter out "any" entries, then sort by min_size self.interval_entries = [] self.min_size_values = [] for entry in size_entries: if entry["min_size"] != "any" and entry["max_size"] != "any": self.interval_entries.append(entry) self.min_size_values.append(entry["min_size"]) # Sort entries by min_size to enable binary search for fast lookups self.interval_entries.sort(key=lambda x: x["min_size"]) self.min_size_values = [entry["min_size"] for entry in self.interval_entries] def get_name(self, load_size): # Use binary search to find the relevant interval quickly index = bisect.bisect_right(self.min_size_values, load_size) - 1 if index >= 0: matching_entry = self.interval_entries[index] if matching_entry["min_size"] <= load_size <= matching_entry["max_size"]: return matching_entry["name"] # Fall back to the "any" entry if no interval matches if self.fallback_entry: return self.fallback_entry["name"] # Edge case: no entries at all (return None or handle as needed) return None # Initialize your data and mapper (do this once, not per lookup!) my_size_entries = [ {"name": "bob01", "min_size": 0, "max_size": 100, "capacity": 200}, {"name": "bob02", "min_size": 101, "max_size": 1000, "capacity": 100}, {"name": "bob03", "min_size": 1001, "max_size": 5000, "capacity": 50}, {"name": "bob04", "min_size": 5001, "max_size": 10000, "capacity": 25}, {"name": "bob05", "min_size": 10001, "max_size": 50000, "capacity": 12}, {"name": "bob06", "min_size": 50001, "max_size": 100000, "capacity": 6}, {"name": "bob07", "min_size": 100001, "max_size": 150000, "capacity": 3}, {"name": "bob08", "min_size": "any", "max_size": "any", "capacity": 1} ] mapper = SizeToNameMapper(my_size_entries) # Test the mapper with random loads for _ in range(10): load = random.randint(0, 170000) print(f"My load is {load}") assigned_name = mapper.get_name(load) print(f"Mr {assigned_name} can handle this load\n")
Why This Is Better Than the Original Code
Let’s break down the key improvements:
- No More Hidden Logic: The original code uses
try-exceptto catch type errors when comparing "any" to integers—this is confusing for other developers reading your code. Our class explicitly separates fallback and interval logic. - Faster Lookups: By sorting interval entries and using
bisect(binary search), we reduce lookup time from O(n) (linear scan) to O(log n). This is a huge win if you’re doing thousands of lookups. - One-Time Preprocessing: Data is sorted and filtered once during class initialization, not every time you call
get_name. - Clearer Intent: The class name and method names make it obvious what the code does. You can easily modify or extend this class later (e.g., add validation for entries, support multiple fallback entries).
How It Works
- Initialization:
- We first grab the "any" entry to use as a fallback if no interval matches.
- We filter out interval entries (those without "any" values) and sort them by
min_size. This lets us use binary search to quickly find the right interval.
- Lookup:
bisect_rightfinds the position where our load size would fit in the sortedmin_sizelist. We subtract 1 to get the index of the largestmin_sizethat’s less than or equal to our load.- We check if the load falls within that entry’s
max_sizerange. If yes, return the name. - If no interval matches, return the fallback "any" entry’s name.
This implementation maintains exactly the same behavior as your original code but is far easier to work with long-term.
内容的提问来源于stack exchange,提问作者Vidya
相关产品推荐
相关产品推荐

