dart-lang / core

This repository is home to core Dart packages.
https://pub.dev/publishers/dart.dev
BSD 3-Clause "New" or "Revised" License
18 stars 6 forks source link

`partition` suggestion #618

Open Nhowka opened 3 years ago

Nhowka commented 3 years ago

I found the package after reinventing some functions it had and it almost fulfilled all my needs. Thanks for the great work!

The one function I missed (coming from an F# background) was the partition. There, partition takes a list and return a tuple, where the first list are all elements that passed the test and the second, all the elements that didn't.

As dart has no support for tuples, I thought about using a combine function that uses both Iterables and create a new object from them. Here is some naive code of what it could look like inside an extension on Iterable<T>:

  R partition<R>(bool Function(T element) test,
          R Function(Iterable<T> passed, Iterable<T> rejected) combine) =>
      combine(this.where(test), this.whereNot(test));

I plan to use it to sort some mixed data from the server, where some of it is already fully loaded while the other part needs further loading. Then I can queue the loading of just the second list while showing the first.

Not sure if this is too niche of a case to be on the library. What do you think?

JulianBissekkou commented 3 years ago

I wrote this a few days ago and I would love to have this added to the library.

malthee commented 5 days ago

Its been some time, but i think this is a common issue and would fit well into the collection package.

lrhn commented 1 day ago

The issue is that it's not a good iterable operation.

It's a better (but not great) Stream operation, if you listen on both result streams at the same time.

The partition function on iterables would basically be:

extension <T> on Iterable<T> {
  (List<T> included, List<T> excluded) partition(bool Function(T) includeTest) {
    var included = <T>[], excluded = <T>[];
    for (var element in this) {
      (includeTest(element) ? included : excluded).add(element);
    }
    return (included, excluded);
  }
}

It's just iterating all the elements and putting them into different buckets, then returning the completed buckets.

Which means it's basically groupBy again, specialized for booleans and list output:

extension <T> on Iterable<T> {
  (List<T> included, List<T> excluded) partition(bool Function(T) includeTest) {
    var g = this.groupListsBy(includeTest);
    return (g[true] ?? <T>[], g[false] ?? <T>[]);
  }
}

Not sure that small specialization is worth its own function. (Not sure groupBy existed when this issue was first created.)