[swift-evolution] Proposal: Filter split extension on Sequence to return tuple of sequences that meet criteria and that do not

plx plxswift at icloud.com
Thu Jun 9 11:22:50 CDT 2016


This reminds me of something: I *very* often wish the standard library had an analog to `NSIndexSet`.

I bring it up b/c it would allow, here, for IMHO a rather nice way to write the *eager* variant of this `filterSplit` (or preferably imho, `partition`, if not for the *other* `partition` out there) function:

  extension Collection {

    /// Returns the index-sets upon which `predicate(self[$index])` evaluates to `true` and `false`, respectively, 
    func partitionedIndices(predicate: (Element) -> Bool) -> (IndexSet<Self.Index>, IndexSet<Self.Index>)

  }

…from which—with a suitable IndexSet implementation!—it would then be easy to construct filtered views into the original collections (and even filtered collections, at least for e.g. range-replaceable collections).

It’d be nice to see such a type make it in at some point!

In the interim, a reasonable “primitive” it’d be nice to have in the standard library would be some methods like this:

  extension Collection {

     func classified<T:Equatable>(classifier: (Element) -> T) -> [(T,Range<Self.Index>)]
     func lazilyClassified<T:Equatable>(classifier: (Element) -> T) -> LazyClassificationSequence<Self,T>

  }

…for which the semantics should be s.t. the below is a correct implementation of `filterSplit` (spelling them out more-precisely is doable but tedious):

  extension RangeReplaceableCollection {

    func filterSplit(predicate: (Element) -> Bool) -> (Self,Self) {
      guard !self.isEmpty else { return (Self(), Self() }
      var trues: Self = Self()
      var falses: Self = Self()
      for (classification,range) in self.lazilyClassified(predicate) {
        switch classification {
          case true: trues.appendContents(of: self[range])
          case false: falses.appendContents(of: self[range])
        }
      }
      return (trues,falses)
    }

  }

…which could also be generalized further (e.g. for T:Hashable, to then return `[T:Self]`, etc.).

Such “classification” methods would have broader-uses than implementing `filterSplit`; is there a specific reason something analogous isn’t already in the standard library (or shouldn’t be)?

Likewise, would an `IndexSet` type be something that could make it into the standard library at some point? (It'd have some API-design issues to sort out under collections-move-indices, but nothing that seems truly insurmountable.)

> On Jun 8, 2016, at 10:10 AM, gadiraju praneeth via swift-evolution <swift-evolution at swift.org> wrote:
> 
> Many times, I came across a scenario where I had to filter an array with a condition and filter the same array with opposite of that condition. For example:
> 
> let values = [2, 4, 3, 5, 6, 9]
> 
> let divisibleByTwo = values.filter { $0 % 2 == 0 }
> let notDivisibleByTwo = values.filter { $0 % 2 != 0 }
> 
> Is there a way currently where we can filter the array into two arrays based on a condition?
> 
> If not how about something like a filterSplit function where we get a tuple of values:
> 
> values.filterSplit { $0 % 2 == 0 } = ([2,4,6], [3,5,9])
> 
> I have implemented this in our project and wanted to get your thoughts on it
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution



More information about the swift-evolution mailing list