Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert first N item in iterable to Array

Something similar to question Convert ES6 Iterable to Array. But I only want first N items. Is there any built-in for me to do so? Or how can I achieve this more elegantly?

let N = 100;
function *Z() { for (let i = 0; ; i++) yield i; }

// This wont work
// Array.from(Z()).slice(0, N);
// [...Z()].slice(0, N)

// This works, but a built-in may be preferred
let a = [], t = Z(); for (let i = 0; i < N; i++) a.push(t.next().value);
like image 928
tsh Avatar asked Nov 29 '17 01:11

tsh


People also ask

What does array from() do?

Array.from() lets you create Array s from: iterable objects (objects such as Map and Set ); or, if the object is not iterable, array-like objects (objects with a length property and indexed elements).

What is IterableIterator?

It's explained in detail here: " IterableIterator is an interface defined by TypeScript that combines the contracts of Iterables and Iterator into one. This is because, in some cases, it makes sense to have the Iterable as an Iterator itself, removing the need to have an external class that serves as the iterator."

What is JS iterable?

The iterable protocol allows JavaScript objects to define or customize their iteration behavior, such as what values are looped over in a for...of construct. Some built-in types are built-in iterables with a default iteration behavior, such as Array or Map , while other types (such as Object ) are not.


2 Answers

To get the first n values of an iterator, you could use one of:

Array.from({length: n}, function(){ return this.next().value; }, iterator);
Array.from({length: n}, (i => () => i.next().value)(iterator));

To get the iterator of an arbitrary iterable, use:

const iterator = iterable[Symbol.iterator]();

In your case, given a generator function Z:

Array.from({length: 3}, function(){ return this.next().value; }, Z());

If you need this functionality more often, you could create a generator function:

function* take(iterable, length) {
  const iterator = iterable[Symbol.iterator]();
  while (length-- > 0) yield iterator.next().value;
}

// Example:
const set = new Set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
console.log(...take(set, 3));
like image 99
le_m Avatar answered Sep 30 '22 11:09

le_m


There is no built in method to take only a certain number of items from an iterable (ala something like take()). Although your snippet can be somewhat improved with a for of loop, which is specifically meant to work with iterables, eg:

let a = []; let i = 0; for (let x of Z()) { a.push(x); if (++i === N) break; }

Which might be better since your original snippet would continue looping even if there are not N items in the iterable.

like image 43
CRice Avatar answered Sep 30 '22 11:09

CRice