1

I'm working on some Swift code to run through an array of strings (teams) and if special characters from another array (charsToRemove) are present, remove the item from the teams array. Alternatively, I'd also be OK with adding items that do NOT contain a special character to an array as well. Here is some sample data:

teams = ["lime", "teal/gold", "red-2", "orange", "orange(6)", "blue-7" ... ]
charsToRemove = [ "(", ")", "-", " ", "/" ... ]

The final result should look like:

teams = ["lime", "orange"]

I've tried a few iterations of loops but looking for what might be the best route. The teams array and special characters is a bit longer but didn't want to paste too much on here.

1
  • It's useful to understand the mindset behind the answers. Your questions boils down into two parts: "Remove string from array if" -> That's a filter(_:) operation, if specific characters present in swift -> so we need to determine what the predicate is for filter(_:). From there, people gravitated to either using Array.contains(_:) or CharacterSet(_:). It's useful to break down problems into sub-problems like this Commented Jan 21, 2018 at 3:08

3 Answers 3

1

You can use String method rangeOfCharacter(from: CharacterSet) to check if it finds a range of a character set and use it to filter your array:

let teams = ["lime", "teal/gold", "red-2", "orange", "orange(6)", "blue-7"]
let charsToRemove = [ "(", ")", "-", " ", "/" ]
let cs = CharacterSet(charactersIn: charsToRemove.joined())
let filtered = teams.filter({ $0.rangeOfCharacter(from: cs) == nil })
print(filtered)   // ["lime", "orange"]
Sign up to request clarification or add additional context in comments.

Comments

1

A more reusable (and cleaner IMHO) approach of Leo's answer is to extend Array:

extension Array where Element == String {
    /// Returns a new array after applying the filter
    var cleaned: [Element] {
        let charSet = CharacterSet(charactersIn: " ()-/") // note the space
        return filter { $0.rangeOfCharacter(from: charSet) == nil }
    }
}

let teams = ["lime", "teal/gold", "red-2", "orange", "orange(6)", "blue-7"]
print(teams.cleaned) // prints: ["lime", "orange"]

Or extend Sequence if you want to broaden its application:

extension Sequence where Element == String {
    /// Returns a new array after applying the filter
    var cleaned: [Element] {
        let charSet = CharacterSet(charactersIn: " ()-/") // note the space
        return filter { $0.rangeOfCharacter(from: charSet) == nil }
    }
}

let teams = ["lime", "teal/gold", "red-2", "orange", "orange(6)", "blue-7"]
print(teams.cleaned) // prints: ["lime", "orange"]

let set = Set(teams)
print(set.cleaned) // prints: ["orange", "lime"]

(Note: Set's are not ordered)

Comments

0

You can use a single filter operation on your Array. Inside the filter, you just need to call charsToRemove.contains(where:) to check if teamName contains any of the elements of charsToRemove and if it doesn't, keep the team name in the filtered array.

let teams = ["lime", "teal/gold", "red-2", "orange", "orange(6)", "blue-7" ]
let charsToRemove = [ "(", ")", "-", " ", "/"]
let filteredTeams = teams.filter({ teamName -> Bool in
    charsToRemove.contains(where: { teamName.contains($0) }) == false
})

3 Comments

return keyword is redundant and the ternary condition ? true : false is redundant too charsToRemove.contains { teamName.contains($0)} == false }
filter { !charsToRemove.contains(where: $0.contains) }
== false ? true : false ... yikes. As Leo said, filter { !charsToRemove.contains(where: $0.contains) } is a good option, but some people also prefer charsToRemove.contains { teamName.contains($0)} == false }, because the ! can be hard to see at first glance

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.