Home >Web Front-end >JS Tutorial >Fluent Streams: A Library for Rich Iterables Manipulation

Fluent Streams: A Library for Rich Iterables Manipulation

Susan Sarandon
Susan SarandonOriginal
2024-12-15 16:24:16209browse

Fluent Streams: A Library for Rich Iterables Manipulation

Artwork: https://code-art.pictures/

Imagine a library that:

  • Like Ramda, provides many useful functions for iterables manipulation
  • Reads familiar, like standard Array iterative methods
  • Doesn't try to replace JavaScript built-ins like Array, Set, or the iteration protocol
  • Like Java Streams, includes Optional to clearly distinguish between “no value” and “undefined as a value”
  • Is compact in terms of bundle size

I couldn't find one that fits all these needs, so I created my small library — fluent-streams.

Talk is Cheap. Show Me the Code

Top 3 Words in a Text

const words = ['Lorem', 'ipsum', /* ... */]
stream(words)
  .groupBy(word => word.toLowerCase())
  .map(([word, list]) => [word, list.length])
  .sortBy(([, length])  => -length)
  .take(3)
  .toArray()

// => ['ut', 3], ['in', 3], ['dolor', 2]

Coprime Integers

// Endless stream of 2..999 integers
const randomInts = continually(() => 
  2 + Math.floor(Math.random() * 998)
)

randomInts
  .zip(randomInts)
  .filter(([a, b]) => gcd(a, b) === 1)
  .distinctBy(pair => stream(pair).sortBy(i => i).join())
  .take(10)

// => [804, 835], [589, 642], [96, 145], ...
  • Streams can be endless, as shown, but you can limit them to the first n items using the take(n) method
  • A stream can be reused multiple times, even in parallel. This is because streams are stateless and only store a reference to the input. The state is created only when the stream spawns an iterator.

Generate a Deck of Cards

const deck = streamOf('♠', '♥', '♣', '♦')
  .flatMap(suit =>
    streamOf<string | number>(
      'A',
      ...range(2, 11),
      'J',
      'Q',
      'K'
    ).map(rank => `${rank}${suit}`)
  )

// => 'A♠', '2♠', '3♠', ...

And Play Hold'em Poker!

  const playersNum = 2
  const [flop, turn, river, ...hands] = deck
    .takeRandom(3 + 1 + 1 + playersNum * 2)
    .zipWithIndex()
    .splitWhen((_, [, j]) =>
      j === 3            // flop
      || j === 4         // turn
      || j >= 5          // river
         && j % 2 === 1  // ...players' hands
    )
    .map(chunk =>
      // Unzip index
      chunk.map(([card]) => card)
    )

// flop = ['3♦', '9♣', 'J♦']
// turn = ['4♣']
// river = ['7♦']
// hands = ['J♠', '4♥'], ['10♠', '8♥']

First player has a pair of Jacks on the flop, while the second player gets a straight, but only on the river. Who will win?

This Must Be Cheap

Everything above can be achieved with only native data structures. However, code written with Fluent Streams reads nicer. While making code more readable is a perfectly valid goal, the cost of achieving it should be low in terms of cognitive load, bundle size, and performance.

And that’s exactly the case with Fluent Streams! Here’s why:

  • No learning curve: The API feels familiar, resembling standard Array methods. It’s easy to add and just as easy to remove.
  • No reinvention: The library doesn’t create new data structures or protocols — it builds on JavaScript’s already robust features.
  • Minimal bundle impact: At just 8.5 kB minified, it’s lightweight. If your project already includes React and its satellite libraries, which weigh hundreds of kilobytes, this addition is hardly noticeable.
  • Lazy processing: The library processes items lazily, which can reduce memory usage and improve efficiency in long pipelines by avoiding unnecessary intermediate data copying.

Caveats

The library is shipped untranspiled to ES5. This decision is driven by the desire to maintain a small bundle size, which is achieved by leveraging ES6 features that enable iteration with very concise code — most notably generators. However, only widely supported language features are utilized.

If you are still transpiling to ES5, you can use the library by transpiling it yourself and adding polyfills. Be aware, though, that this will increase the bundle size, so it’s not recommended. Instead, this might be the perfect occasion to revisit your build configuration and embrace modern JavaScript features.

Have Fun Coding!

The above is the detailed content of Fluent Streams: A Library for Rich Iterables Manipulation. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn