jaccardAsymmetric<T> function
Asymmetric Jaccard: |Q ∩ C| / (|Q| + weight * |C|).
Treats query as the "small" side and candidate as the "large" side.
A small weight (default 0.3) softens the penalty for the catalog being
larger than the query — useful when matching short descriptive tokens
against a long classname or constructor signature.
Returns 1.0 only when query ⊆ candidate AND candidate is empty
(which can't happen if the intersection is non-empty); otherwise less
than 1.0.
Implementation
double jaccardAsymmetric<T>(
Set<T> query,
Set<T> candidate, {
double weight = 0.3,
}) {
if (query.isEmpty && candidate.isEmpty) return 1.0;
final intersection = query.intersection(candidate).length;
final denominator = query.length + weight * candidate.length;
if (denominator == 0) return 0.0;
return intersection / denominator;
}