I'm would like to get some help wrapping my head around simplifying this code. This works but I'm thinking there Must be a simpler way.
Goal:
- Replace all VirtualRide w/ Ride
- If Both VirtualRide and Ride exists in array, remove VirtualRide
eg:
input = ["Ride", "VirtualRide", "Run", "VirtualRun"] output = ["Ride", "Run"]
input = ["VirtualRide", "VirtualRun"] output = ["Ride", "Run"]
input = ["Ride", "Run"] output = ["Ride", "Run"] (Basically do nothing)
let sportsArray = ["Ride", "VirtualRide"]
var newSportsArray = sportsArray // sportsArray is passed in. So it's a Let
let ixVirtualRide = sportsArray.firstIndex(of: "VirtualRide")
if let ixVirtualRide = ixVirtualRide {
if newSportsArray.filter({$0.contains("Ride")}).count > 1 {
newSportsArray.remove(at: ixVirtualRide)
}
if newSportsArray.filter({$0.contains("VirtualRide")}).count == 1 {
newSportsArray.remove(at: ixVirtualRide)
newSportsArray.append("Ride")
}
}
CodePudding user response:
If the goal is to remove any Virtual occurrence, delete the substring if matched:
sportsArray = sportsArray.map{$0.contains("Virtual") ? $0.replacingOccurrences(of: "Virtual", with: "") : $0}
Then, if the array cannot contain anything else than those four elements, use a set to clear duplicates:
let unique = Array(Set(sportsArray))
CodePudding user response:
Here we import OrderedCollections from the Swift package library because we want to use an Ordered set to remove duplicates but maintain order:
import OrderedCollections
If Virtual isn't always at the start, and never appears anywhere else, you can use replacingOccurrences(of:) otherwise a handy extension on String helps here:
extension String {
func deletingPrefix(_ prefix: String) -> String {
guard hasPrefix(prefix) else { return self }
return String(dropFirst(prefix.count))
}
}
Now we can make a function that takes the array of strings and removes the prefixes and deduplicates the results, maintaining the order of them.
func f(_ s: [String]) -> [String] {
Array(OrderedSet(s.map { $0.deletingPrefix("Virtual") }))
}
Then
f(["Ride", "VirtualRide", "Run", "VirtualRun"] // = ["Ride", "Run"]
etc for all your example inputs.
If you prefer this style you can write it like this too:
func makePrefixDeleter(_ p: String) -> (String) -> String {
return { str in
str.deletingPrefix(p)
}
}
let deleteVirtualPrefix = makePrefixDeleter("Virtual")
func f(_ s: [String]) -> [String] {
Array(OrderedSet(s.map(deleteVirtualPrefix)))
}
Which might be handy if you have a use for the "Virtual" prefix deleter function in other places.
The other approach that suggests itself is to standardise your input via an enum (essentially parsing it), like:
enum Thing {
case ride
case run
init?(_ s: String) {
switch s {
case "Ride", "VirtualRide":
self = .ride
case "Run", "VirtualRun":
self = .run
default:
return nil
}
}
var str: String {
switch self {
case .ride: return "Ride"
case .run: return "Run"
}
}
}
let example = OrderedSet(["Ride", "VirtualRide", "Run", "VirtualRun"].compactMap(Thing.init(_:)).map(\.str)))
CodePudding user response:
Your specifications are incomplete and don't match your examples. I guess you want to
- remove the prefix
Virtual
- remove duplicates (e.g. drop the
Ride
fromVirtualRide
if there is anotherRide
) - preserve alphabetic order (avoid
["Ride", "Run"]
)
Below code will still work when you introduce VirtualLift
:
let newSportsArray = Set( // 2. remove duplicates
sportsArray.map {
$0.replacingOccurrences(of: "Virtual", with: "") // 1. remove prefix
})
.sorted() // 3. prevent arbitrary order in Set and convert to Array