Home Manual Reference Source

src/group.js

import {iter} from '@iterable-iterator/iter';

/**
 * Yields elements of the input iterable by grouping them into tuples
 * consecutive elements from the same equivalence class.
 *
 * @example
 * // A B C D A B
 * list( map( ( [ k , g ] ) => k , group( x => x , 'AAAABBBCCDAABBB' ) ) )
 *
 * @example
 * // AAAA BBB CC D
 * list( map( ( [ k , g ] ) => list( g ) , group( x => x , 'AAAABBBCCD' ) ) )
 *
 * @param {Function} key - The function used to determine the equivalence class
 * of an element.
 * @param {Iterable} iterable - The input iterable.
 * @returns {Iterator}
 */
export default function* group(key, iterable) {
	const iterator = iter(iterable);

	const first = iterator.next();

	if (first.done) {
		return;
	}

	let currval = first.value;
	let currkey = key(currval);

	const grouper = function* (tgtkey) {
		while (true) {
			yield currval;

			const event = iterator.next();
			if (event.done) {
				return;
			}

			currval = event.value;
			currkey = key(currval);

			if (currkey !== tgtkey) {
				return;
			}
		}
	};

	while (true) {
		const tgtkey = currkey;

		const g = grouper(tgtkey);

		yield [tgtkey, g];

		while (currkey === tgtkey) {
			const event = iterator.next();
			if (event.done) {
				return;
			}

			currval = event.value;
			currkey = key(currval);
		}
	}
}