Home > Enterprise >  Simplify my code for Searching and Replacing Strings in an Array
Simplify my code for Searching and Replacing Strings in an Array

Time:08-20

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"]  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

  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
  • Related