joinMap<TInner, TKey, TResult> method

Iterable<TResult> joinMap<TInner, TKey, TResult>(
  1. Iterable<TInner> inner,
  2. TResult resultSelector(
    1. T element,
    2. TInner otherElement
    ), {
  3. TKey outerKeySelector(
    1. T element
    )?,
  4. TKey innerKeySelector(
    1. TInner otherElement
    )?,
  5. EqualityComparer<TKey>? keyComparer,
})

Finds keys in this iterable with matching keys in the inner collection and returns a value that is the result of the corresponding elements being merged.

First, joinMap will iterate over the inner collection and make a lookup table of its elements, referenceable by a key generated by innerKeySelector. Then joinMap will iterate over the source iteration, generating keys via the outerKeySelector. If a generated key matches a key in the collection lookup, the collection element and the iterable element are passed through the resultSelector. The returned value of resultSelector is then added to the resulting iterable.

Elements in the source iterable that doesn't share a key in the lookup table as well as elements in inner that don't share a key with a source iterable element are discarded.

Example:

void main() {
  final a = {'1': 1, '2': 2, '3': 3, '4': 4};
  final b = {'1': 1.0, '2': 2.0, '3': 3.0, '5': 5.0};

  final result = a.entries.joinMap(
    b.entries,
    (x, y) => '${x.value}: ${y.value}',
    outerKeySelector: (x) => x.key,
    innerKeySelector: (y) => y.key,
  );

  // Result: ['1: 1.0', '2: 2.0', '3: 3.0']
}

Implementation

Iterable<TResult> joinMap<TInner, TKey, TResult>(
  Iterable<TInner> inner,
  TResult Function(T element, TInner otherElement) resultSelector, {
  TKey Function(T element)? outerKeySelector,
  TKey Function(TInner otherElement)? innerKeySelector,
  EqualityComparer<TKey>? keyComparer,
}) sync* {
  outerKeySelector ??= (T v) => v as TKey;
  innerKeySelector ??= (TInner v) => v as TKey;
  keyComparer ??= EqualityComparer.forType<TKey>();

  final lookup = Lookup.createForJoin(inner, innerKeySelector, keyComparer);

  final outerIterator = iterator;

  Iterator<TInner>? groupIterator;

  TKey outerKey;
  T outerValue;
  Grouping<TKey, TInner>? grouping;
  while (outerIterator.moveNext()) {
    outerValue = outerIterator.current;
    outerKey = outerKeySelector(outerIterator.current);
    grouping = lookup.getGrouping(outerKey, false);

    if (grouping != null) {
      groupIterator = grouping.iterator;

      while (groupIterator.moveNext()) {
        yield resultSelector(outerValue, groupIterator.current);
      }

      groupIterator = null;
    }
  }
}