55832

Remove last elements of a collection while a condition in Swift

<h3>Question</h3>

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 " "?
Thanks.


<h3>Answer1:</h3>

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.


<h3>Answer2:</h3>

Move your condition to while and make sure you're checking on the correct array after the operation.

<pre class="lang-swift prettyprint-override">var array = ["A", "B", "", "C", "D", " ", " ", ""] while array.last == " " || array.last == "" { array.removeLast() } print(array) // ["A", "B", "", "C", "D"]
<h3>Answer3:</h3>

Just for fun, lets extend Array with this functionality in a generic way while also externally providing the condition for more flexibility.

Similar to Arrays having a drop(while:), we can make a dropLast(while:) like so:

extension Array { func dropLast(while handler: (Element)->Bool) -> Array { var array = self while let last = array.last, handler(last) { array.removeLast() } return array } } <hr /><h3>Usage Example:</h3> let array = ["", "A", "B", "", "C", "D", " ", " ", ""] let modified = array.dropLast { $0.trimmingCharacters(in: .whitespaces).isEmpty } print(modified) //["", "A", "B", "", "C", "D"] <hr /><h3>Bonus:</h3>

It can handle other types of arrays too, and since the condition is not baked into the functionality, it's flexible and reusable.

let array = [0, 1, 2, 3, 0, 5, 6, 7, 0, -1, 0, -2] //Drop (from tail) all numbers less than 1 let modified = array.dropLast(while: { (val) -> Bool in return val < 1 }) print(modified) //[0, 1, 2, 3, 0, 5, 6, 7]
<h3>Answer4:</h3>

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] } } <hr />"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)...) } } <hr />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"]
<h3>Answer5:</h3>

Basically your solution plays fine. But you can make it more generic for "", " ", "", " ", .... :

import Foundation var array = ["A", "B", "", "C", "D", " ", " ", ""] while true { let shouldRemoveLast = array.last?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? false if (shouldRemoveLast) { array.removeLast() } else { break } }

来源:https://stackoverflow.com/questions/55138253/remove-last-elements-of-a-collection-while-a-condition-in-swift

Recommend

  • Get mdslider value in angular 2?
  • Console input in TypeScript
  • Isolated Storage, OOB, and Removing the App
  • Maven Pom.xml Auto Increment Version
  • Manually highlight Wordpress admin menu item
  • “net use” command in a Windows Service
  • Error “The OneDriveForBusiness for this user account cannot be retrieved.” when accessing Microsoft
  • Angular4 refresh page repeats page in url
  • stepped color shading in highcharts doughnut chart
  • how to redirect. old url to new url. [Laravel, htacces]
  • Rebus: 2 handlers in 2 processes. Hit inconsistently and alternately
  • Normal Query on Cassandra using DataStax Enterprise works, but not solr_query
  • Creating Neural Network for un-encountered inputs
  • Running ASP.NET Web Api 2 application without Visual Studio
  • VB.Net Exception has been thrown by the target of an invocation
  • Download local file in angularJS
  • How to efficiently work with multiple database tables in Ruby on Rails
  • When scaling and drawing an image to canvas in iOS Safari, width is correct but height is squished
  • In Moment.js, how do you get the date of the next occurrence of a specific month (ex: 'next Jan
  • how to add Image in JPanel
  • Why am I getting an Argument exception when creating event handler dynamically?
  • Write to elasticsearch from spark is very slow
  • Auto send email based on the time and email address in database
  • ASP.NET GridView throws: The version of SQL Server in use does not support datatype 'date'
  • How can I filter an array of dictionaries in 'updateSearchResultsForSearchController' to s
  • Issue with Terrain Collision using Three.js
  • How to use AJAX to upload large CSV file? [closed]
  • Change the color of the legend text in forceNetwork for networkD3
  • openpyxl - adding new rows in excel file with merged cell existing
  • VS2010 RDLC C#. How can I set a LocalReport object to a ReportViewer?
  • Cloud Code: Creating a Parse.File from URL
  • Bad automatic Triangulation with Mayavi for coloring a surface known only by its corner