如何最小化多对多哈希表(Hashtable)中的条目数量?
Hey there! Let me break down this problem for you—you’re absolutely right that this ties back to classic algorithm concepts, and there’s a straightforward, efficient way to solve this without reinventing the wheel.
First off, the core problem you’re tackling is essentially finding equivalent groups of keys that share identical sets of values (or vice versa), and this maps directly to ideas from itemset mining—specifically, working with closed itemsets (though we can simplify things since we don’t need "frequency" thresholds here).
Let me walk through this clearly with your example:
Your input pairs are A-1, B-1, B-2, B-3, C-2, C-3. The standard one-to-many map gives you 3 entries, but you want to collapse this into 2 entries by grouping keys that share the same values.
The Key Insight: Reverse the Mapping
The trick here is to flip your initial key-to-values map into a value-to-keys map first. Here’s why:
- For each value, collect all keys that are linked to it. In your example, this gives:
1: {A,B}, 2: {B,C}, 3: {B,C} - Now, any values that map to the exact same set of keys can be grouped together. Since 2 and 3 both link to B and C, we can bundle them under the key group [B,C]. Value 1 links to A and B, so it gets its own group [A,B].
This gives you the minimal number of entries because we’ve eliminated all redundancy—every entry represents a unique group of keys that share a unique set of values, with no overlaps that can be collapsed further.
Python Implementation (Simple & Efficient)
Here’s how to turn this logic into code, with time complexity O(N + M) (N = number of input pairs, M = number of unique values)—way faster than any savings you’ll get from reducing entries:
from collections import defaultdict # Your input pairs input_links = [("A", 1), ("B", 1), ("B", 2), ("B", 3), ("C", 2), ("C", 3)] # Step 1: Build the initial key-to-values map (one-to-many) key_to_vals = defaultdict(set) for key, val in input_links: key_to_vals[key].add(val) # Step 2: Reverse it to value-to-keys map val_to_keys = defaultdict(set) for key, vals in key_to_vals.items(): for val in vals: val_to_keys[val].add(key) # Step 3: Group values by their shared key sets (use sorted tuples for hashability) keyset_to_vals = defaultdict(set) for val, keys in val_to_keys.items(): sorted_key_tuple = tuple(sorted(keys)) keyset_to_vals[sorted_key_tuple].add(val) # Step 4: Convert to your desired format (lists instead of sets if needed) minimized_map = {list(keys): list(vals) for keys, vals in keyset_to_vals.items()} print(minimized_map) # Output: {['A', 'B']: [1], ['B', 'C']: [2, 3]}
Why This Guarantees Minimal Entries
This approach ensures you can’t get fewer entries because every entry corresponds to a unique combination of keys that share a unique set of values. There’s no way to merge any two entries without breaking the one-to-one correspondence between key groups and their value sets.
Existing Algorithms/Libraries
If you’re working with massive datasets, you could use itemset mining libraries like mlxtend (which implements Apriori and other itemset algorithms), but for most cases, rolling your own code as above is simpler and more efficient—since we don’t need the "frequency filtering" that those libraries are designed for.
内容的提问来源于stack exchange,提问作者Curtis6566

