I am attempting to remove ""
& " "
from the back of a string array until the last item contains some text, but my implementation isn't picking up " "
.
My implementation so far:
var array = ["A", "B", "", "C", "D", " ", " ", ""]
while true {
if (array.last == " " || array.last == "") {
array.removeLast()
} else {
break
}
}
My desired output is
["A", "B", "", "C", "D"]
, but my current output is
["A", "B", "", "C", "D", " ", " "]
, where the while
loop simply breaks
after encountering " "
Any advice why is it not picking up the " "
?
I don't know why they have drop(while:)
and did not implement dropLast(while:)
. The implementation bellow works on any collection:
extension Collection {
func dropLast(while predicate: (Element) throws -> Bool) rethrows -> SubSequence {
guard let index = try indices.reversed().first(where: { try !predicate(self[$0]) }) else {
return self[startIndex..<startIndex]
}
return self[...index]
}
}
"123".dropLast(while: \.isWholeNumber) // ""
"abc123".dropLast(while: \.isWholeNumber) // "abc"
"123abc".dropLast(while: \.isWholeNumber) // "123abc"
And extending RangeReplaceableCollection we can implement remove(while:)
and removeLast(while:)
as well:
extension RangeReplaceableCollection {
mutating func remove(while predicate: (Element) throws -> Bool) rethrows {
guard let index = try indices.first(where: { try !predicate(self[$0]) }) else {
removeAll()
return
}
removeSubrange(..<index)
}
mutating func removeLast(while predicate: (Element) throws -> Bool) rethrows {
guard let index = try indices.reversed().first(where: { try !predicate(self[$0]) }) else {
removeAll()
return
}
removeSubrange(self.index(after: index)...)
}
}
var string = "abc123"
string.removeLast(while: \.isWholeNumber)
string // "abc"
var string2 = "abc123"
string2.remove(while: \.isLetter)
string2 // "123"
var array = ["A", "B", "", "C", "D", " ", " ", ""]
array.removeLast { $0 == "" || $0 == " " }
array // ["A", "B", "", "C", "D"]
One way to solve this is to reverse the collection (which is done lazily) and drop the unwanted items until you encounter the wanted ones. Afterwards, reverse the collection again.
let array = ["A", "B", "", "C", "D", " ", " ", ""]
let filtered = array.reversed().drop(while: {
$0.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
}).reversed() as [String]
print(filtered) // "["A", "B", "", "C", "D"]\n"
Note that the check for " "
may fail if it's not a normal space, for example a non-breaking space (Unicode checkpoint U+00A0). This may be the issue you're having in the first place. So trim the string (it removes characters from the start and end only) and check whether the result is an empty string.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With