function zip(datasets) {
	  // manually type-check the argument for JS users
	  if (!isIterable$1(datasets)) {
	    throw new Error('The argument to zip() must be an object or array.');
	  }

	  var size;

	  if (Array.isArray(datasets)) {
	    for (var i = 0; i < datasets.length; i++) {
	      size = size == null ? datasets[i].size : Math.min(size, datasets[i].size);
	    }
	  } else if (datasets instanceof Object) {
	    for (var ds in datasets) {
	      size = size == null ? datasets[ds].size : Math.min(size, datasets[ds].size);
	    }
	  }

	  return datasetFromIteratorFn( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee17() {
	    var streams;
	    return regeneratorRuntime.wrap(function _callee17$(_context17) {
	      while (1) {
	        switch (_context17.prev = _context17.next) {
	          case 0:
	            _context17.next = 2;
	            return deepMapAndAwaitAll(datasets, function (d) {
	              if (d instanceof Dataset) {
	                return {
	                  value: d.iterator(),
	                  recurse: false
	                };
	              } else if (isIterable$1(d)) {
	                return {
	                  value: null,
	                  recurse: true
	                };
	              } else {
	                throw new Error('Leaves of the structure passed to zip() must be Datasets, ' + 'not primitives.');
	              }
	            });

	          case 2:
	            streams = _context17.sent;
	            return _context17.abrupt("return", iteratorFromZipped(streams, ZipMismatchMode.SHORTEST));

	          case 4:
	          case "end":
	            return _context17.stop();
	        }
	      }
	    }, _callee17);
	  })), size);
	}
Create a `Dataset` by zipping together an array, dict, or nested
structure of `Dataset`s (and perhaps additional constants).
The underlying datasets must provide elements in a consistent order such that
they correspond.

The number of elements in the resulting dataset is the same as the size of
the smallest dataset in datasets.

The nested structure of the `datasets` argument determines the
structure of elements in the resulting iterator.

Note this means that, given an array of two datasets that produce dict
elements, the result is a dataset that produces elements that are arrays
of two dicts:

Zip an array of datasets:
```js
console.log('Zip two datasets of objects:');
const ds1 = tf.data.array([{a: 1}, {a: 2}, {a: 3}]);
const ds2 = tf.data.array([{b: 4}, {b: 5}, {b: 6}]);
const ds3 = tf.data.zip([ds1, ds2]);
await ds3.forEachAsync(e => console.log(JSON.stringify(e)));

// If the goal is to merge the dicts in order to produce elements like
// {a: ..., b: ...}, this requires a second step such as:
console.log('Merge the objects:');
const ds4 = ds3.map(x => {return {a: x[0].a, b: x[1].b}});
await ds4.forEachAsync(e => console.log(e));
```

Zip a dict of datasets:
```js
const a = tf.data.array([{a: 1}, {a: 2}, {a: 3}]);
const b = tf.data.array([{b: 4}, {b: 5}, {b: 6}]);
const c = tf.data.zip({c: a, d: b});
await c.forEachAsync(e => console.log(JSON.stringify(e)));
```

@doc {heading: 'Data', subheading: 'Operations', namespace: 'data'}