Skip to content

Commit

Permalink
[stdlib] Introduce filterMap and deprecate one flatMap variant
Browse files Browse the repository at this point in the history
This is the implementation of
[SE-0187](https://github.com/apple/swift-evolution/blob/master/proposals/0187-introduce-filtermap.md)

<rdar://problem/34918180>
  • Loading branch information
Max Moiseev committed Dec 18, 2017
1 parent 8e967ad commit 6f7aecd
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 7 deletions.
50 changes: 47 additions & 3 deletions stdlib/public/core/FlatMap.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ extension LazySequenceProtocol {
FlattenSequence<LazyMapSequence<Elements, SegmentOfResult>>> {
return self.map(transform).joined()
}

/// Returns the non-`nil` results of mapping the given transformation over
/// this sequence.
///
Expand All @@ -39,7 +39,7 @@ extension LazySequenceProtocol {
///
/// - Complexity: O(1)
@_inlineable // FIXME(sil-serialize-all)
public func flatMap<ElementOfResult>(
public func filterMap<ElementOfResult>(
_ transform: @escaping (Elements.Element) -> ElementOfResult?
) -> LazyMapSequence<
LazyFilterSequence<
Expand All @@ -48,6 +48,28 @@ extension LazySequenceProtocol {
> {
return self.map(transform).filter { $0 != nil }.map { $0! }
}

/// Returns the non-`nil` results of mapping the given transformation over
/// this sequence.
///
/// Use this method to receive a sequence of nonoptional values when your
/// transformation produces an optional value.
///
/// - Parameter transform: A closure that accepts an element of this sequence
/// as its argument and returns an optional value.
///
/// - Complexity: O(1)
@inline(__always)
@available(*, deprecated, renamed: "filterMap(_:)")
public func flatMap<ElementOfResult>(
_ transform: @escaping (Elements.Element) -> ElementOfResult?
) -> LazyMapSequence<
LazyFilterSequence<
LazyMapSequence<Elements, ElementOfResult?>>,
ElementOfResult
> {
return self.filterMap(transform)
}
}

extension LazyCollectionProtocol {
Expand All @@ -69,7 +91,28 @@ extension LazyCollectionProtocol {
> {
return self.map(transform).joined()
}


/// Returns the non-`nil` results of mapping the given transformation over
/// this collection.
///
/// Use this method to receive a collection of nonoptional values when your
/// transformation produces an optional value.
///
/// - Parameter transform: A closure that accepts an element of this
/// collection as its argument and returns an optional value.
///
/// - Complexity: O(1)
@_inlineable // FIXME(sil-serialize-all)
public func filterMap<ElementOfResult>(
_ transform: @escaping (Elements.Element) -> ElementOfResult?
) -> LazyMapCollection<
LazyFilterCollection<
LazyMapCollection<Elements, ElementOfResult?>>,
ElementOfResult
> {
return self.map(transform).filter { $0 != nil }.map { $0! }
}

/// Returns the non-`nil` results of mapping the given transformation over
/// this collection.
///
Expand All @@ -80,6 +123,7 @@ extension LazyCollectionProtocol {
/// collection as its argument and returns an optional value.
///
/// - Complexity: O(1)
@available(*, deprecated, renamed: "filterMap(_:)")
@_inlineable // FIXME(sil-serialize-all)
public func flatMap<ElementOfResult>(
_ transform: @escaping (Elements.Element) -> ElementOfResult?
Expand Down
38 changes: 35 additions & 3 deletions stdlib/public/core/SequenceAlgorithms.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,37 @@ extension Sequence {
}

extension Sequence {
/// Returns an array containing the non-`nil` results of calling the given
/// transformation with each element of this sequence.
///
/// Use this method to receive an array of nonoptional values when your
/// transformation produces an optional value.
///
/// In this example, note the difference in the result of using `map` and
/// `filterMap` with a transformation that returns an optional `Int` value.
///
/// let possibleNumbers = ["1", "2", "three", "///4///", "5"]
///
/// let mapped: [Int?] = possibleNumbers.map { str in Int(str) }
/// // [1, 2, nil, nil, 5]
///
/// let flatMapped: [Int] = possibleNumbers.filterMap { str in Int(str) }
/// // [1, 2, 5]
///
/// - Parameter transform: A closure that accepts an element of this
/// sequence as its argument and returns an optional value.
/// - Returns: An array of the non-`nil` results of calling `transform`
/// with each element of the sequence.
///
/// - Complexity: O(*m* + *n*), where *m* is the length of this sequence
/// and *n* is the length of the result.
@_inlineable
public func filterMap<ElementOfResult>(
_ transform: (Element) throws -> ElementOfResult?
) rethrows -> [ElementOfResult] {
return try _filterMap(transform)
}

/// Returns an array containing the non-`nil` results of calling the given
/// transformation with each element of this sequence.
///
Expand All @@ -751,19 +782,20 @@ extension Sequence {
///
/// - Complexity: O(*m* + *n*), where *m* is the length of this sequence
/// and *n* is the length of the result.
@_inlineable
@inline(__always)
@available(*, deprecated, renamed: "filterMap(_:)")
public func flatMap<ElementOfResult>(
_ transform: (Element) throws -> ElementOfResult?
) rethrows -> [ElementOfResult] {
return try _flatMap(transform)
return try _filterMap(transform)
}

// The implementation of flatMap accepting a closure with an optional result.
// Factored out into a separate functions in order to be used in multiple
// overloads.
@_inlineable // FIXME(sil-serialize-all)
@inline(__always)
public func _flatMap<ElementOfResult>(
public func _filterMap<ElementOfResult>(
_ transform: (Element) throws -> ElementOfResult?
) rethrows -> [ElementOfResult] {
var result: [ElementOfResult] = []
Expand Down
10 changes: 9 additions & 1 deletion stdlib/public/core/StringRangeReplaceableCollection.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -438,10 +438,18 @@ extension Sequence {

extension Collection {
@_inlineable // FIXME(sil-serialize-all)
public func filterMap(
_ transform: (Element) throws -> String?
) rethrows -> [String] {
return try _filterMap(transform)
}

@available(*, deprecated, renamed: "filterMap(_:)")
@inline(__always)
public func flatMap(
_ transform: (Element) throws -> String?
) rethrows -> [String] {
return try _flatMap(transform)
return try _filterMap(transform)
}
}
//===----------------------------------------------------------------------===//
Expand Down

0 comments on commit 6f7aecd

Please sign in to comment.