Q:

Full outer Join in LINQ optimized for unique keys

Presume these two ordered sequences (the elements are unique):
var outer = new char[] { 'a', 'b', 'c', 'other' };
var inner = new char[] { 'a', 'b', 'c', 'altro' };

The desired result is the Full Outer Join:
{ 'a', 'a' }
{ 'b', 'b' }
{ 'c', 'c' }
{ 'other', '' }
{ '', 'altro' }

The Full Outer Join can be achieved in LINQ in this way (it's an answer on SO): LINQ - Full Outer Join
But this solution doesn't takes in account that the elements from both sequences are unique. How can the algorithm be optimized?  

A:

Based on the referenced answer I tried something that doesn't create Lookup's but Dictionary's instead.
IMHO that's the only thing you can cut that will actually save some time.
Skipping creation of the HashSet (as proposed in my rushed comment) is not an option as this will lead to the duplication of all joined pairs.
public static class Extensions {
    public static IEnumerable<TResult> FullOuterJoin<TA, TB, TKey, TResult>(
        this IEnumerable<TA> a,
        IEnumerable<TB> b,
        Func<TA, TKey> selectKeyA,
        Func<TB, TKey> selectKeyB,
        Func<TA, TB, TKey, TResult> projection,
        TA defaultA = default(TA),
        TB defaultB = default(TB),
        IEqualityComparer<TKey> cmp = null) {

        cmp = cmp ?? EqualityComparer<TKey>.Default;
        var adict = a.ToDictionary(selectKeyA, cmp);
        var bdict = b.ToDictionary(selectKeyB, cmp);

        var keys = new HashSet<TKey>(adict.Keys, cmp);
        keys.UnionWith(bdict.Keys);

        var join = from key in keys
                   let xa = adict.GetOrDefault(key, defaultA)
                   let xb = bdict.GetOrDefault(key, defaultB)
                   select projection(xa, xb, key);

        return join;
    }

    public static T GetOrDefault<K, T>(this IDictionary<K, T> d, K k, T def = default(T)) 
        => d.TryGetValue(k, out T value) ? value : def;
}

