skip to Main Content

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:

  1. Replace all VirtualRide w/ Ride
  2. If Both VirtualRide and Ride exists in array, remove VirtualRide

eg:

input = ["Ride", "VirtualRide", "Run", "VirtualRun"]  expected output = ["Ride", "Run"]
input = ["VirtualRide", "VirtualRun"]                 expected output = ["Ride", "Run"]
input = ["Ride", "Run"]                               expected output = ["Ride", "Run"] (Basically do nothing)

This is the current code that works, but is just seems ugly and long.

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")
  }
}

3

Answers


  1. 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))
    
    Login or Signup to reply.
  2. 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)))
    
    Login or Signup to reply.
  3. Your specifications are incomplete and don’t match your examples. I guess you want to

    1. remove the prefix Virtual
    2. remove duplicates (e.g. drop the Ride from VirtualRide if there is another Ride)
    3. 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
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search