/**
 * Group items in an iterable based on some key.
 * @param items
 * @param key
 */
export function* groupBy<T, K>(items: ReadonlyArray<T> | IterableIterator<T>, key: (item: T) => K): IterableIterator<Array<T>> {
  let chunk: { items: Array<T>; key: K } | null = null;
  for (const item of items) {
    const itemKey = key(item);
    if (chunk === null) {
      chunk = {
        items: [item],
        key: itemKey
      };
    } else if (itemKey === chunk.key) {
      chunk.items.push(item);
    } else {
      yield chunk.items;
      chunk = {
        items: [item],
        key: itemKey
      };
    }
  }
  if (chunk !== null) {
    yield chunk.items;
  }
}
