(function (global, factory) {
	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
	typeof define === 'function' && define.amd ? define(factory) :
	(global = global || self, global.pick = factory());
}(this, (function () { 'use strict';

	var shallowProperty = key => obj => obj == null ? void 0 : obj[key];

	var getLength = shallowProperty('length');

	const MAX_ARRAY_INDEX = 2 ** 53 - 1;

	var isArrayLike = (collection) => {
		const length = getLength(collection);

		return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
	};

	var isFunction = obj => toString.call(obj) === '[object Function]';

	var isObject = obj => {
		const type = typeof obj;

		return type === 'function' || type === 'object' && !!obj;
	};

	var isArguments = obj => toString.call(obj) === '[object Arguments]';

	var identity = value => value;

	var getKeys = (obj) => {
		if (!isObject(obj)) return [];

		return Object.keys(obj);
	};

	const deepGet = (obj, path) => {
		const { length } = path;

		for (let i = 0; i < length; i++) {
			if (obj == null) return void 0;
			obj = obj[path[i]];
		}

		return length ? obj : void 0;
	};

	var property = path => {
		if (!Array.isArray(path)) {
			return shallowProperty(path);
		}

		return obj => deepGet(obj, path);
	};

	var isMatch = (object, attrs) => {
		const keys = getKeys(attrs);
		const {length} = keys;

		if (object == null) return !length;
		const obj = Object(object);

		for (let i = 0; i < length; i++) {
			const key = keys[i];

			if (attrs[key] !== obj[key] || !(key in obj)) return false;
		}

		return true;
	};

	var matcher = attrs => {
		attrs = Object.assign({}, attrs);

		return obj => isMatch(obj, attrs);
	};

	var optimizeCb = (func, context, argCount) => {
		if (context === void 0) return func;
		switch (argCount == null ? 3 : argCount) {
			case 1: return value => func.call(context, value);
				// The 2-argument case is omitted because we’re not using it.
			case 3: return (value, index, collection) => func.call(context, value, index, collection);
			case 4: return (accumulator, value, index, collection) => func.call(context, accumulator, value, index, collection);
		}

		return (...args) => func.apply(context, args);
	};

	const baseIteratee = (value, context, argCount) => {
		if (value == null) return identity;
		if (isFunction(value)) return optimizeCb(value, context, argCount);
		if (isObject(value) && !Array.isArray(value)) return matcher(value);

		return property(value);
	};

	let iteratee;

	const exportIteratee = iteratee = (value, context) => baseIteratee(value, context, Infinity);

	var cb = (value, context, argCount) => {
		if (iteratee !== exportIteratee) return iteratee(value, context);

		return baseIteratee(value, context, argCount);
	};

	var lib = {
		shallowProperty,
		getLength,
		isArrayLike,
		isFunction,
		isObject,
		isArguments,
		identity,
		getKeys,
		property,
		matcher,
		isMatch,
		optimizeCb,
		cb
	};

	var forEach = (obj, iteratee, context) => {
		iteratee = optimizeCb(iteratee, context);
		if (isArrayLike(obj)) {
			let i = 0;

			for (const item of obj) {
				iteratee(item, i++, obj);
			}
		} else {
			const keys = getKeys(obj);

			for (const key of keys) {
				iteratee(obj[key], key, obj);
			}
		}

		return obj;
	};

	const flatten = (input, shallow, strict, output = []) => {
		let idx = output.length;

		forEach(input, value => {
			if (isArrayLike(value) && (Array.isArray(value) || isArguments(value))) {
				if (shallow) {
					let j = 0;
					const len = value.length;

					while (j < len) output[idx++] = value[j++];
				} else {
					flatten(value, shallow, strict, output);
					idx = output.length;
				}
			} else if (!strict) {
				output[idx++] = value;
			}
		});

		return output;
	};

	var flatten_1 = (array, shallow) => flatten(array, shallow, false);

	var map = (obj, iteratee, context) => {
		iteratee = cb(iteratee, context);
		const keys = !isArrayLike(obj) && getKeys(obj);
		const { length } = keys || obj;
		const results = Array(length);

		for (let index = 0; index < length; index++) {
			const currentKey = keys ? keys[index] : index;

			results[index] = iteratee(obj[currentKey], currentKey, obj);
		}

		return results;
	};

	const {
		getLength: getLength$1,
		isArrayLike: isArrayLike$1,
		isFunction: isFunction$1,
		isObject: isObject$1,
		isArguments: isArguments$1,
		identity: identity$1,
		getKeys: getKeys$1,
		property: property$1,
		matcher: matcher$1,
		isMatch: isMatch$1,
		optimizeCb: optimizeCb$1,
		cb: cb$1
	} = lib;




	const isNumber = obj => toString.call(obj) === '[object Number]';

	const isString = obj => toString.call(obj) === '[object String]';

	const isUndefined = obj => obj === void 0;

	const has = (obj, path) => obj != null && Object.prototype.hasOwnProperty.call(obj, path);

	const hasProperty = (obj, path) => {
		if (!Array.isArray(path)) {
			return has(obj, path);
		}
		const { length } = path;

		for (let i = 0; i < length; i++) {
			const key = path[i];

			if (obj == null || !Object.prototype.hasOwnProperty.call(obj, key)) {
				return false;
			}
			obj = obj[key];
		}

		return !!length;
	};

	const constant = value => () => value;

	const keyInObj = (value, key, obj) => key in obj;

	const allKeys = obj => {
		if (!isObject$1(obj)) return [];
		const keys = [];

		for (const key in obj) keys.push(key);

		return keys;
	};

	const values = (obj) => {
		const keys = getKeys$1(obj);
		const { length } = keys;
		const values = Array(length);

		for (let i = 0; i < length; i++) {
			values[i] = obj[keys[i]];
		}

		return values;
	};

	const toPairs = (obj) => {
		const keys = getKeys$1(obj);
		const pairs = [];

		for (const key of keys) {
			pairs.push([key, obj[key]]);
		}

		return pairs;
	};

	const noop = () => {};

	const initial = (array, n, guard) => Array.prototype.slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));

	const createPredicateIndexFinder = dir => (array, predicate, context) => {
		predicate = cb$1(predicate, context);
		const length = getLength$1(array);
		let index = dir > 0 ? 0 : length - 1;

		for (; index >= 0 && index < length; index += dir) {
			if (predicate(array[index], index, array)) return index;
		}

		return -1;
	};

	const findIndex = createPredicateIndexFinder(1);

	const range = (start, stop, step) => {
		if (stop == null) {
			stop = start || 0;
			start = 0;
		}
		if (!step) {
			step = stop < start ? -1 : 1;
		}

		const length = Math.max(Math.ceil((stop - start) / step), 0);
		const range = Array(length);

		for (let idx = 0; idx < length; idx++, start += step) {
			range[idx] = start;
		}

		return range;
	};

	const findKey = (obj, predicate, context) => {
		predicate = cb$1(predicate, context);
		const keys = getKeys$1(obj);
		let key;

		for (let i = 0, { length } = keys; i < length; i++) {
			key = keys[i];
			if (predicate(obj[key], key, obj)) return key;
		}
	};

	const find = (obj, predicate, context) => {
		const keyFinder = isArrayLike$1(obj) ? findIndex : findKey;
		const key = keyFinder(obj, predicate, context);

		if (key !== void 0 && key !== -1) return obj[key];
	};

	const filter = (obj, predicate, context) => {
		const results = [];

		predicate = cb$1(predicate, context);
		forEach(obj, (value, index, list) => {
			if (predicate(value, index, list)) results.push(value);
		});

		return results;
	};

	const reStrSymbol = /[^\ud800-\udfff]|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff]/g;

	const toArray = (obj) => {
		if (!obj) return [];
		if (Array.isArray(obj)) return Array.prototype.slice.call(obj);
		if (isString(obj)) {
			// Keep surrogate pair characters together
			return obj.match(reStrSymbol);
		}
		if (isArrayLike$1(obj)) return map(identity$1);

		return values(obj);
	};

	const first = (array, n, guard) => {
		if (array == null || array.length < 1) return n == null ? void 0 : [];
		if (n == null || guard) return array[0];

		return initial(array, array.length - n);
	};

	var packageUtils = {
		getLength: getLength$1,
		isArrayLike: isArrayLike$1,
		optimizeCb: optimizeCb$1,
		isFunction: isFunction$1,
		isNumber,
		isArguments: isArguments$1,
		isString,
		isUndefined,
		isObject: isObject$1,
		getKeys: getKeys$1,
		hasProperty,
		property: property$1,
		isMatch: isMatch$1,
		matcher: matcher$1,
		findKey,
		identity: identity$1,
		constant,
		keyInObj,
		allKeys,
		values,
		toPairs,
		cb: cb$1,
		noop,
		forEach,
		map,
		find,
		filter,
		toArray,
		first,
		initial,
		flatten: flatten_1,
		findIndex,
		range
	};

	const {
		keyInObj: keyInObj$1,
		allKeys: allKeys$1,
		optimizeCb: optimizeCb$2,
		isFunction: isFunction$2,
		flatten: flatten$1
	} = packageUtils;

	var pickUtil = (obj, ...keys) => {
		const result = {};
		let [iteratee] = keys;

		if (!obj) {
			return result;
		}

		if (isFunction$2(iteratee)) {
			if (keys.length > 1) iteratee = optimizeCb$2(iteratee, keys[1]);
			keys = allKeys$1(obj);
		} else {
			iteratee = keyInObj$1;
			keys = flatten$1(keys);
			obj = Object(obj);
		}

		keys.forEach(key => {
			const value = obj[key];

			if (iteratee(value, key, obj)) {
				result[key] = value;
			}
		});

		return result;
	};

	return pickUtil;

})));
