I’ve updated some of my programming tutorial exercises with Swift code samples. See the original exercise for complete problem description. Swift 2.1 code tested in Xcode 7.2 Playground.

The anagram problem

A string is an anagram of another string if re-arranging the letters results in the other string. “Astronomer” and “moon-starer!” are anagrams.

In the original problem we stripped all punctuation since symbols and spaces may be ignored. Let’s say we wanted to count “Ray.adverb” as a single word (for whatever reason) including the period, but “ray-adverb” should still ignore the hyphen as normal. In the code below we strip by word boundaries.

Swift 2.1: are two strings anagrams
import Cocoa
var str1 = "Astronomer!"
var str2 = " Moon starer?"
var str3 = "ray-adverb"
var str4 = "barry-dave."
var str5 = "Ray.Adverb"
var str6 = "Tom Marvolo-Riddle"
var str7 = "I am Lord Voldemort!"
func areAnagrams(phrase1: String, phrase2: String) -> Bool
{
if phrase1.isEmpty { return false }
if phrase2.isEmpty { return false }
//var trimmedPhrase1 = phrase1.stringByReplacingOccurrencesOfString(" ", withString: "")
//var trimmedPrhase2 = phrase2.stringByReplacingOccurrencesOfString(" ", withString: "")
var trimmedPhrase1 = stripWordBoundaries(phrase1)
var trimmedPrhase2 = stripWordBoundaries(phrase2)
trimmedPhrase1 = trimmedPhrase1.lowercaseString
trimmedPrhase2 = trimmedPrhase2.lowercaseString
if trimmedPrhase2 == trimmedPhrase1 {
return false
}
if trimmedPrhase2.characters.count != trimmedPhrase1.characters.count {
return false
}
let chars1 = trimmedPhrase1.characters.sort()
let chars2 = trimmedPrhase2.characters.sort()
if chars1 == chars2 {
return true
}
return false
}
// let's treat "Ray.adverb" as a word so period would not be stripped, but "Adverb-Ray?" would become AdverbRay
func stripWordBoundaries(string: String) -> String
{
var words : [String] = []
string.enumerateSubstringsInRange(string.characters.indices,
options: .ByWords) {
(substring, _, _, _) -> () in
words.append(substring!)
}
return words.joinWithSeparator("")
}
func anagramTest(phrase1 ph1: String, phrase2 ph2: String)
{
if areAnagrams(ph1, phrase2: ph2) {
print("'\(ph1)' and '\(ph2)' are anagrams")
}
else {
print("'\(ph1)' and '\(ph2)' are NOT anagrams")
}
}
anagramTest(phrase1: str1, phrase2: str2)
anagramTest(phrase1: str3, phrase2: str4)
anagramTest(phrase1: str5, phrase2: str4)
anagramTest(phrase1: str6, phrase2: str7)

The sum-zero triplet problem

We want to check if a set of integers contains three integers that sum to zero. See original problem for complete description and alternate solutions.

Swift 2.1: find sum-zero triplet
import Cocoa
// test numbers
let numArray1 = [ 0, 5, -2, 2, -3, 42, 10 ];
let numArray2 = [ 1, 4, 0, 7, 3 ];
let numArray3 = [ 10, 4, -4, 8, 0 ];
let testArray = [ -2, -1, -3, 4, -5, 6 ];
// return an optional tupple; returns nil of none exist
//
func findTripletSumZero(inIntegers intArray: [Int]) -> (Int, Int, Int)?
{
if intArray.count < 3 {
return nil
}
let sortedArray = intArray.sort()
// all positives never sum zero
if sortedArray[0] > 0 {
return nil
}
// check from each end and adjust according to sorted order
for i in 0 ..< sortedArray.count
{
var left = i + 1;
var right = sortedArray.count - 1
// squeeze until right crosses paths with left
while right > left
{
let sum = sortedArray[i] + sortedArray[left] + sortedArray[right]
if sum == 0
{
return (sortedArray[i], sortedArray[left], sortedArray[right])
}
else if sum > 0 {
right -= 1
}
else {
left += 1
}
}
}
return nil
}
func performTest(inIntegers intArray: [Int])
{
let test = findTripletSumZero(inIntegers: intArray)
if (test == nil) {
print("Array \(intArray) has no triplet which sum zero.")
}
else {
let firstInt = test!.0
let secondInt = test!.1
let thirdInt = test!.2
print("Array \(intArray) has zero-sum triplet: (\(firstInt),\(secondInt),\(thirdInt)).")
}
}
performTest(inIntegers: testArray)
performTest(inIntegers: numArray1)
performTest(inIntegers: numArray2)
performTest(inIntegers: numArray3)

## Palindrome check

In Swift 2, a String is not a sequence type so we use String.CharacterView (astring.characters). There are a number of ways to loop through a CharacterView, but since we want to compare characters at two indices then let’s convert to an Array. See the original problem for details.

Swift: is the string a palindrome?
import Cocoa
func phraseIsPalindrome(phrase: String) -> Bool
{
let regex = try! NSRegularExpression(pattern: "[\\s\\p{P}]", options: [.CaseInsensitive])
let trimmedPhrase = regex.stringByReplacingMatchesInString(phrase, options:[], range: NSMakeRange(0, phrase.characters.count), withTemplate: "")
if trimmedPhrase.characters.count > 1 {
let charArray = Array(trimmedPhrase.lowercaseString.characters)
// go to mid-point while checking for same character on other end
for i in 0 ..< len / 2 + 1 {
if charArray[i] != charArray[charArray.count - i - 1] {
return false
}
}
return true
}
else if trimmedPhrase.characters.count == 1 {
// allow single-character phrase
return true
}
return false
}
phraseIsPalindrome("Never odd or even.") // true
phraseIsPalindrome("Never odd or evan") // false
phraseIsPalindrome("Madam, I'm Adam!") // true