-
Notifications
You must be signed in to change notification settings - Fork 442
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
105 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the Swift Algorithms open source project | ||
// | ||
// Copyright (c) 2020 Apple Inc. and the Swift project authors | ||
// Licensed under Apache License v2.0 with Runtime Library Exception | ||
// | ||
// See https://swift.org/LICENSE.txt for license information | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
extension BidirectionalCollection { | ||
|
||
/// Returns a `SubSequence` formed by discarding all elements at the start and end of the Collection | ||
/// which satisfy the given predicate. | ||
/// | ||
/// Trimming is a common operation in computing, often referring to removing leading and trailing whitespace | ||
/// from a string[1]. | ||
/// | ||
/// ``` | ||
/// let myString = " hello, world " | ||
/// print(myString.trimmed(where: \.isWhitespace)) // "hello, world" | ||
/// ``` | ||
/// | ||
/// [1]: https://en.wikipedia.org/wiki/Trimming_(computer_programming) | ||
/// | ||
/// - parameters: | ||
/// - predicate: A closure which determines if the element should be omitted from the resulting slice. | ||
/// | ||
/// - complexity: `O(n)`, where `n` is the length of the Collection. | ||
/// | ||
@inlinable | ||
public func trimmed(where predicate: (Element) throws -> Bool) rethrows -> SubSequence { | ||
|
||
// Consume elements from the front. | ||
let sliceStart = try firstIndex(where: { try predicate($0) == false }) ?? endIndex | ||
// sliceEnd is the index _after_ the last index to match the predicate. | ||
var sliceEnd = endIndex | ||
while sliceStart != sliceEnd { | ||
let idxBeforeSliceEnd = index(before: sliceEnd) | ||
guard try predicate(self[idxBeforeSliceEnd]) else { | ||
return self[sliceStart..<sliceEnd] | ||
} | ||
sliceEnd = idxBeforeSliceEnd | ||
} | ||
return self[Range(uncheckedBounds: (sliceStart, sliceStart))] // Trimmed everything. | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the Swift Algorithms open source project | ||
// | ||
// Copyright (c) 2020 Apple Inc. and the Swift project authors | ||
// Licensed under Apache License v2.0 with Runtime Library Exception | ||
// | ||
// See https://swift.org/LICENSE.txt for license information | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
import XCTest | ||
import Algorithms | ||
|
||
final class TrimTests: XCTestCase { | ||
|
||
func testEmpty() { | ||
let results_empty = ([] as [Int]).trimmed { $0.isMultiple(of: 2) } | ||
XCTAssertEqual(results_empty, []) | ||
} | ||
|
||
func testNoMatch() { | ||
// No match (nothing trimmed). | ||
let results_nomatch = [1, 3, 5, 7, 9, 11, 13, 15].trimmed { $0.isMultiple(of: 2) } | ||
XCTAssertEqual(results_nomatch, [1, 3, 5, 7, 9, 11, 13, 15]) | ||
} | ||
|
||
func testNoTailMatch() { | ||
// No tail match (only trim head). | ||
let results_notailmatch = [1, 3, 5, 7, 9, 11, 13, 15].trimmed { $0 < 10 } | ||
XCTAssertEqual(results_notailmatch, [11, 13, 15]) | ||
} | ||
|
||
func testNoHeadMatch() { | ||
// No head match (only trim tail). | ||
let results_noheadmatch = [1, 3, 5, 7, 9, 11, 13, 15].trimmed { $0 > 10 } | ||
XCTAssertEqual(results_noheadmatch, [1, 3, 5, 7, 9]) | ||
} | ||
|
||
func testBothEndsMatch() { | ||
// Both ends match, some string of >1 elements do not match (return that string). | ||
let results = [2, 10, 11, 15, 20, 21, 100].trimmed(where: { $0.isMultiple(of: 2) }) | ||
XCTAssertEqual(results, [11, 15, 20, 21]) | ||
} | ||
|
||
func testEverythingMatches() { | ||
// Everything matches (trim everything). | ||
let results_allmatch = [1, 3, 5, 7, 9, 11, 13, 15].trimmed { _ in true } | ||
XCTAssertEqual(results_allmatch, []) | ||
} | ||
|
||
func testEverythingButOneMatches() { | ||
// Both ends match, one element does not match (trim everything except that element). | ||
let results_onematch = [2, 10, 12, 15, 20, 100].trimmed { $0.isMultiple(of: 2) } | ||
XCTAssertEqual(results_onematch, [15]) | ||
} | ||
} |