Tracking specific data in string using Swift - ios

I'm still new to coding in general, and I'm running into an issue with a Swift exercise.
How do I track the number of times 1 (var numberOfSteps) and the number of times 2 (var numberOfHeartBeats) appears in the string "12221231221"?
I'm given the following hint but not sure how the for-in loop applies:
let activityData = "12221231221"
var numberOfSteps = 0
var numberOfHeartBeats = 0
for character in activityData{
print(character)
}

In the loop, you can check what the current characters is, then increment the variable accordingly:
let activityData = "12221231221"
var numberOfSteps = 0
var numberOfHeartBeats = 0
for character in activityData{
if character == "1" {
numberOfSteps += 1
} else if character == "2" {
numberOfHeartBeats += 1
}
}
Here is another more functional way of doing this:
let dict = Dictionary(grouping: activityData, by: { $0 }).mapValues { $0.count }
dict["1"] is numberOfSteps and dict["2"] is numberOfHeartBeats.

If you want to use a for loop you can do
let activityData = "12221231221"
var numberOfSteps = 0
var numberOfHeartBeats = 0
for character in activityData{
switch character {
case "1":
numberOfSteps += 1
case "2":
numberOfHeartBeats += 1
default:
break
}
}
print("Number of steps: \(numberOfSteps), number of hartbeats: \(numberOfHeartBeats)")
A more condensed solution without a loop
print("Number of steps: \( activityData.filter( {$0 == "1"} ).count), number of hartbeats: \( activityData.filter( {$0 == "2"} ).count)")

You can do this in simple way like this:-
let occurrencesOne = text.characters.filter { $0 == "1" }.count
let occurrencesTwo = text.characters.filter { $0 == "2" }.count

Another solution is to use reduce, this is kinda equivalent to manually looping over the string, but will less and mode concise code, and without the disadvantage of creating intermediary structures (like arrays of dictionaries), which for large inputs can be problematic memory-wise:
let activityData = "12221231221"
let numberOfSteps = activityData.reduce(0) { $1 == "1" ? $0 + 1 : $0 }
let numberOfHeartBeats = activityData.reduce(0) { $1 == "2" ? $0 + 1 : $0 }
print(numberOfSteps, numberOfHeartBeats) // 4, 6
One step further to reduce the duplication would be to add a function to compute the reduce second parameter:
func countIf<T: Equatable>(_ search: T) -> (Int, T) -> Int {
return { $1 == search ? $0 + 1 : $0 }
}
let activityData = "12221231221"
let numberOfSteps: Int = activityData.reduce(0, countIf("1"))
let numberOfHeartBeats = activityData.reduce(0, countIf("2"))
print(numberOfSteps, numberOfHeartBeats)

Related

Find the Missing no from an array the efficient way

I am trying to find an efficient way to solve the find a missing number from an array. I implemented the following way it's O(n). Please write any codes that efficiently solves this, just for learning purpose.
func findMissingNo(arrA: [Int]) -> [Int] {
let firstIndex = arrA.first ?? 0
let lastIndex = arrA.last ?? 0
let rslt = Array(firstIndex...lastIndex)
let missingNoArray = rslt.filter{ !arrA.contains($0)}
return missingNoArray
}
findMissingNo(arrA: [11,12,14,15,16,18]) // Prints [13, 17] by looping 9 times
Quickly written and tested (in terms of times performances against your code, but not in term of possible edges cases/mistakes, for instance, if array is 0...10, it won't work, but I'll let you work on the edges cases, since I focused mainly on the main cases, cases which might be covered during an edit and the end of the question)
Your current code:
func findMissingNo(arrA: [Int]) -> [Int] {
let firstIndex = arrA.first ?? 0
let lastIndex = arrA.last ?? 0
let rslt = Array(firstIndex...lastIndex)
let missingNoArray = rslt.filter{ !arrA.contains($0)}
return missingNoArray
}
let numberArray = [11,12,14,15,18]
let missing1 = findMissingNo(arrA: numberArray)
print("Missing1: \(missing1)")
My attempt:
func findMissingNo2(arrA: [Int]) -> [Int] {
var missingNumbers: [Int] = []
guard arrA.count > 2 else { return missingNumbers }
for i in 0...arrA.count-2 {
var current = arrA[i]
let next = arrA[i+1]
if next != current + 1 {
current += 1
while current != next {
missingNumbers.append(current)
current += 1
}
}
}
return missingNumbers
}
let missing2 = findMissingNo2(arrA: numberArray)
print("Missing1: \(missing2)")
Creating a big batch:
var array = Array(0...1000)
for _ in 0...10 {
if let index = array.indices.randomElement() {
let value = array.remove(at: index)
print("removed: \(value)") //To check just in case that's the good value returned by the methods
}
}
Testing:
let date1 = Date()
for _ in 0...100 {
let missing = findMissingNo(arrA: array)
print(missing)
}
print(Date().timeIntervalSince(date1)) //18.617565035820007
let date2 = Date()
for _ in 0...100 {
let missing = findMissingNo2(arrA: array)
print(missing)
}
print(Date().timeIntervalSince(date2)) //0.09566605091094971
print("---End")
print("")
For the time, I got: 18.857954025268555 vs 0.09159696102142334, a big factor difference (~200 times).
Why is there such a big difference?
Because of
let missingNoArray = rslt.filter{ !arrA.contains($0)}
It means:
for each number in result, check if arrayA contains that number.
->
for each number in result, for each number in arrayA (with a stop condition, so it's not a full iteration, but "almost" in term of complexity) check if there is a match...
Here there is a "double" (which is in fact not double, but n?) iteration that you missed.
I tested first with bigger value (array from "0 to 100000"), but it was taking too much time, with that "low number of values", the difference can already be seen.
Instead, you could use a Set:
let missingNoArray = Array(Set(rslt).subtracting(Set(arrA))).sorted()
It's faster than you method in my tests, (double my solution (0.21 ~ 0.22) in time performances), but still much faster than yours.
I added the sorted(), which may or may not be important in your solution, but will add time consumption since Set aren't ordered.
For the edges cases (ie: [3], [3, 4], [3, 8])
guard arrA.count > 2 else { return missingNumbers }
==>
guard !arrA.isEmpty else { return [] }
guard arrA.count > 2 else {
if arrA[0] + 1 >= arrA[1] {
return []
} else {
return Array((arrA[0] + 1)...arrA[1]).dropLast() //Because last will be arrA[1] which is present)
}
}

How to remove character from odd index in Swift String

I am new to swift & I have to remove characters from odd index from a given String
I did try with following code
var myStringObject = "HelloTestString"
myStringObject.enumerated().filter({ index, char in !(char == "1" && index % 2 == 0) })
but I am unable to find the desired result string. Can you please guide me how to remove characters from odd index in String.
You can't filter by two filter types. So you have to move to the old approach.
var myStringObject = "HelloTestString"
var newString = ""
var index = 0
while index < myStringObject.count {
if index % 2 != 0 {
let firstIndex: String.Index = myStringObject.startIndex
let desiredChar: Character = myStringObject[myStringObject.index(firstIndex, offsetBy: index)]
newString = newString + "\(desiredChar)"
}
index = index + 1
}
print(newString) //elTsSrn
Keeping your starting solution:
let couples = myStringObject.enumerated().filter { (arg0) -> Bool in
let (offset, _) = arg0
return offset % 2 == 0
}
print(couples)
or
let couples = myStringObject.enumerated().filter { (offset, _) -> Bool in
return offset % 2 == 0
} //Which is more similar to last version
You have then, an array of Tuples where first element is the offset, and the second the element.
$>[(offset: 0, element: "H"), (offset: 2, element: "l"), (offset: 4, element: "o"), (offset: 6, element: "e"), (offset: 8, element: "t"), (offset: 10, element: "t"), (offset: 12, element: "i"), (offset: 14, element: "g")]
Let's keep only the letters (and back to String, not a String.Element):
let onlyletters = couples.map({ String($0.element) })
Let's get it back into a String.
let result = onlyletters.joined()
In one line:
let oneLine = myStringObject.enumerated().filter({ $0.0 % 2 == 0 }).map({ String($0.element) }).joined()
You can create an auxiliary index and use defer to increase it after each iteration on your collection, this way you don't need to enumerate your string:
let string = "HelloTestString"
var index = 0
let filtered = string.filter { _ in
defer { index += 1 }
return index % 2 == 1
}
print(filtered) // "elTsSrn"
If you need to mutate your original string you can use removeAll with the same approach:
var string = "HelloTestString"
var index = 0
string.removeAll { _ in
defer { index += 1 }
return index % 2 == 0
}
print(string)
Implementing your own method
extending RangeReplaceableCollection to filter or removeAll elements that are in odd or even positions:
extension RangeReplaceableCollection {
var oddIndicesElements: Self {
var position = 0
return filter { _ in
defer { position += 1 }
return position % 2 == 1
}
}
var evenIndicesElements: Self {
var position = 0
return filter { _ in
defer { position += 1 }
return position % 2 == 0
}
}
mutating func removeAllEvenIndicesElements() {
var position = 0
removeAll { _ in
defer { position += 1 }
return position % 2 == 0
}
}
mutating func removeAllOddIndicesElements() {
var position = 0
removeAll { _ in
defer { position += 1 }
return position % 2 == 1
}
}
}
var myStringObject = "HelloTestString"
print(myStringObject.oddIndicesElements) // "elTsSrn"
myStringObject.removeAllEvenIndicesElements()
print(myStringObject) // "elTsSrn"

Gradually and randomly visualize string

I am currently working on a simple program to gradually and randomly visualize a string in two iteration. Right now I have managed to get the first iteration but I'm not sure how to do the second one. If someone could give any example or advice I would be very grateful. My code looks like this:
let s = "Hello playground"
let factor = 0.25
let factor2 = 0.45
var n = s.filter({ $0 != " " }).count // # of non-space characters
var m = lrint(factor * Double(n)) // # of characters to display
let t = String(s.map { c -> Character in
if c == " " {
// Preserve space
return " "
} else if Int.random(in: 0..<n) < m {
// Replace
m -= 1
n -= 1
return c
} else {
// Keep
n -= 1
return "_"
}
})
print(t) // h_l__ _l_______d
To clarify, I want to use factor2 in the second iteration to print something that randomly add letters on top of t that looks something like this h_l_o pl_g_____d.
Replacing Characters
Starting from #MartinR's code, you should remember the indices that have been replaced. So, I am going to slightly change the code that replaces characters :
let s = "Hello playground"
let factor = 0.25
let factor2 = 0.45
var n = s.filter({ $0 != " " }).count // # of non-space characters
let nonSpaces = n
var m = lrint(factor * Double(n)) // # of characters to display
var indices = Array(s.indices)
var t = ""
for i in s.indices {
let c = s[i]
if c == " " {
// Preserve space
t.append(" ")
indices.removeAll(where: { $0 == i })
} else if Int.random(in: 0..<n) < m {
// Keep
m -= 1
n -= 1
t.append(c)
indices.removeAll(where: { $0 == i })
} else {
// Replace
n -= 1
t.append("_")
}
}
print(t) //For example: _e___ ______ou_d
Revealing Characters
In order to do that, we should calculate the number of characters that we want to reveal:
m = lrint((factor2 - factor) * Double(nonSpaces))
To pick three indices to reveal randomly, we shuffle indices and then replace the m first indices :
indices.shuffle()
var u = t
for i in 0..<m {
let index = indices[i]
u.replaceSubrange(index..<u.index(after: index), with: String(s[index]))
}
indices.removeSubrange(0..<m)
print(u) //For example: _e__o _l__g_ou_d
I wrote StringRevealer struct, that handle all revealing logic for you:
/// Hide all unicode letter characters as `_` symbol.
struct StringRevealer {
/// We need mapping between index of string character and his position in state array.
/// This struct represent one such record
private struct Symbol: Hashable {
let index: String.Index
let position: Int
}
private let originalString: String
private var currentState: [Character]
private let charactersCount: Int
private var revealed: Int
var revealedPercent: Double {
return Double(revealed) / Double(charactersCount)
}
private var unrevealedSymbols: Set<Symbol>
init(_ text: String) {
originalString = text
var state: [Character] = []
var symbols: [Symbol] = []
var count = 0
var index = originalString.startIndex
var i = 0
while index != originalString.endIndex {
let char = originalString[index]
if CharacterSet.letters.contains(char.unicodeScalars.first!) {
state.append("_")
symbols.append(Symbol(index: index, position: i))
count += 1
} else {
state.append(char)
}
index = originalString.index(after: index)
i += 1
}
currentState = state
charactersCount = count
revealed = 0
unrevealedSymbols = Set(symbols)
}
/// Current state of text. O(n) conplexity
func text() -> String {
return currentState.reduce(into: "") { $0.append($1) }
}
/// Reveal one random symbol in string
mutating func reveal() {
guard let symbol = unrevealedSymbols.randomElement() else { return }
unrevealedSymbols.remove(symbol)
currentState[symbol.position] = originalString[symbol.index]
revealed += 1
}
/// Reveal random symbols on string until `revealedPercent` > `percent`
mutating func reveal(until percent: Double) {
guard percent <= 1 else { return }
while revealedPercent < percent {
reveal()
}
}
}
var revealer = StringRevealer("Hello товарищ! 👋")
print(revealer.text())
print(revealer.revealedPercent)
for percent in [0.25, 0.45, 0.8] {
revealer.reveal(until: percent)
print(revealer.text())
print(revealer.revealedPercent)
}
It use CharacterSet.letters inside, so most of languages should be supported, emoji ignored and not-alphabetic characters as well.

Finding a value in an array of arrays (similar to VLOOKUP function in Excel) in Swift

I am quite new to Swift 3 and to programming languages in general. I have the following arrays inside an array and a variable income:
let testArray: [[Double]] = [
[0,0],
[1000,20.5],
[3000,21],
[4000,22.5],
]
var income: Double = 3500
What I want to do is something similar to the VLOOKUP function in Excel: I want to find in the first column of the arrays (i.e. 0, 1000, 3000, 4000) a number which is equal or immediately smaller than my variable. In this case, as income = 3500, the program should return 3000. I tried using filter() but I don't know how to work with the arrays inside the array. Any help appreciated.
You can proceed as follows.
Get the first column of the array:
let firstColumn = testArray.map { $0[0] }
print(firstColumn) // [0.0, 1000.0, 3000.0, 4000.0]
Restrict to those elements which are less than or equal to the
given amount:
let filtered = firstColumn.filter { $0 <= income }
print(filtered) // [0.0, 1000.0, 3000.0]
Get the maximal element of the filtered array. If the elements are
sorted in increasing order then you can use last instead of max():
let result = filtered.max()!
// Or: let result = filtered.last!
print(result) // 3000.0
Putting it all together:
let result = testArray.map { $0[0] }.filter { $0 <= income }.max()!
print(result) // 3000.0
A possible optimization is to combine map and filter into
flatMap:
let result = testArray.flatMap { $0[0] <= income ? $0[0] : nil }.max()!
print(result) // 3000.0
This code assumes that there is at least one matching element,
otherwise last! or max()! would crash. If that is not guaranteed:
if let result = testArray.flatMap( { $0[0] <= income ? $0[0] : nil }).max() {
print(result) // 3000.0
} else {
print("no result")
}
Or provide a default value (0.0 in this example):
let result = testArray.flatMap( { $0[0] <= income ? $0[0] : nil }).max() ?? 0.0
print(result) // 3000.0
Something like this:
let testArray: [[Double]] = [
[0,0],
[1000,20.5],
[3000,21],
[3500,22.5],
[3300,21],
]
let income: Double = 3500
var closest = testArray[0][0]
var closestDif = closest - income
for innerArray in testArray {
let value = innerArray[0]
let thisDif = value - income
guard thisDif <= 0 else {
continue
}
if closestDif < thisDif {
closestDif = thisDif
closest = value
guard closestDif != 0 else {
break
}
}
}
print(closest)

Swift Anagram checker

I am attempting to build an anagram checker for swift. This is my code. In case you don't know an anagram checker checks if two strings have the same characters in them but, order does not matter.
func checkForAnagram(#firstString: String, #secondString: String) -> Bool {
var firstStringArray: [Character] = []
var secondStringArray: [Character] = []
/* if case matters delete the next four lines
and make sure your variables are not constants */
var first = firstString
var second = secondString
first = first.lowercaseString
second = second.lowercaseString
for charactersOne in first {
firstStringArray += [charactersOne]
}
for charactersTwo in second {
secondStringArray += [charactersTwo]
}
if firstStringArray.count != secondStringArray.count {
return false
} else {
for elements in firstStringArray {
if secondStringArray.contains(elements){
return true
} else {
return false
}
}
}
}
var a = "Hello"
var b = "oellh"
var c = "World"
checkForAnagram(firstString: a, secondString: b)
I am getting an error message of.
'[Character]' does not have a member 'contains'
The accepted answer is compact and elegant, but very inefficient if compared to other solutions.
I'll now propose and discuss the implementation of a few variants of anagram checker. To measure performance, I'll use the different variants to find the anagrams of a given word out of an array of 50,000+ words.
// Variant 1: Sorting of Character
// Measured time: 30.46 s
func anagramCheck1(a: String, b: String) -> Bool {
return a.characters.sorted() == b.characters.sorted()
}
This is essentially the solution of the accepted answer, written in Swift 3 syntax. It's very slow because Swift's String, unlike NSString, is based on Character, which handles Unicode characters properly.
A more efficient solution exploits the NSCountedSet class, which allows us to represent a string as a set of characters, each with its own count. Two strings are anagrams if they map to the same NSCountedSet.
Note: checking string lengths as a precondition makes the implementation always more efficient.
// Variant 2: NSCountedSet of Character
// Measured time: 4.81 s
func anagramCheck2(a: String, b: String) -> Bool {
guard a.characters.count == b.characters.count else { return false }
let aSet = NSCountedSet()
let bSet = NSCountedSet()
for c in a.characters {
aSet.add(c)
}
for c in b.characters {
bSet.add(c)
}
return aSet == bSet
}
Better but not excellent. Here, one of the "culprits" is the use of the native Swift Character type (from Swift's String). Moving back to good old Objective-C types (NSString and unichar) makes things more efficient.
// Variant 3: NSCountedSet of unichar
// Measured time: 1.31 s
func anagramCheck3(a: String, b: String) -> Bool {
let aString = a as NSString
let bString = b as NSString
let length = aString.length
guard length == bString.length else { return false }
let aSet = NSCountedSet()
let bSet = NSCountedSet()
for i in 0..<length {
aSet.add(aString.character(at: i))
bSet.add(bString.character(at: i))
}
return aSet == bSet
}
Using NSCountedSet is fine, but before we compare two NSCountedSet objects, we fully populate them. A useful alternative is to fully populate the NSCountedSet for only one of the two strings, and then, while we populate the NSCountedSet for the other string, we fail early if the other string contains a character that is not found in the NSCountedSet of the first string.
// Variant 4: NSCountedSet of unichar and early exit
// Measured time: 1.07 s
func anagramCheck4(a: String, b: String) -> Bool {
let aString = a as NSString
let bString = b as NSString
let length = aString.length
guard length == bString.length else { return false }
let aSet = NSCountedSet()
let bSet = NSCountedSet()
for i in 0..<length {
aSet.add(aString.character(at: i))
}
for i in 0..<length {
let c = bString.character(at: i)
if bSet.count(for: c) >= aSet.count(for: c) {
return false
}
bSet.add(c)
}
return true
}
This is about the best timing we are going to get (with Swift). However, for completeness, let me discuss one more variant of this kind.
The next alternative exploits a Swift Dictionary of type [unichar: Int] to store the number of repetitions for each character instead of NSCountedSet. It's slightly slower than the previous two variants, but we can reuse it later to obtain a faster implementation.
// Variant 5: counting repetitions with [unichar:Int]
// Measured time: 1.36
func anagramCheck5(a: String, b: String) -> Bool {
let aString = a as NSString
let bString = b as NSString
let length = aString.length
guard length == bString.length else { return false }
var aDic = [unichar:Int]()
var bDic = [unichar:Int]()
for i in 0..<length {
let c = aString.character(at: i)
aDic[c] = (aDic[c] ?? 0) + 1
}
for i in 0..<length {
let c = bString.character(at: i)
let count = (bDic[c] ?? 0) + 1
if count > aDic[c] ?? 0 {
return false
}
bDic[c] = count
}
return true
}
Note that a vanilla Objective-C implementation using NSCountedSet, corresponding to Variant 3, is faster than all the previous versions by a rather large margin.
// Variant 6: Objective-C and NSCountedSet
// Measured time: 0.65 s
- (BOOL)anagramChecker:(NSString *)a with:(NSString *)b {
if (a.length != b.length) {
return NO;
}
NSCountedSet *aSet = [[NSCountedSet alloc] init];
NSCountedSet *bSet = [[NSCountedSet alloc] init];
for (int i = 0; i < a.length; i++) {
[aSet addObject:#([a characterAtIndex:i])];
[bSet addObject:#([b characterAtIndex:i])];
}
return [aSet isEqual:bSet];
}
Another way we can improve upon the previous attempts is to observe that, if we need to find the anagram of a given word, we might as well consider that word as fixed, and thus we could build the corresponding structure (NSCountedSet, Dictionary, ...) for that word only once.
// Finding all the anagrams of word in words
// Variant 7: counting repetitions with [unichar:Int]
// Measured time: 0.58 s
func anagrams(word: String, from words: [String]) -> [String] {
let anagrammedWord = word as NSString
let length = anagrammedWord.length
var aDic = [unichar:Int]()
for i in 0..<length {
let c = anagrammedWord.character(at: i)
aDic[c] = (aDic[c] ?? 0) + 1
}
let foundWords = words.filter {
let string = $0 as NSString
guard length == string.length else { return false }
var bDic = [unichar:Int]()
for i in 0..<length {
let c = string.character(at: i)
let count = (bDic[c] ?? 0) + 1
if count > aDic[c] ?? 0 {
return false
}
bDic[c] = count
}
return true
}
return foundWords
}
Now, in the previous variant we have counted with a [unichar:Int] Dictionary. This proves slightly more efficient than using an NSCountedSet of unichar, either with early exit (0.60 s) or without (0.87 s).
You should try
func checkForAnagram(firstString firstString: String, secondString: String) -> Bool {
return firstString.lowercaseString.characters.sort() == secondString.lowercaseString.characters.sort()
}
func checkAnagrams(str1: String, str2: String) -> Bool {
guard str1.count == str2.count else { return false }
var dictionary = Dictionary<Character, Int>()
for index in 0..<str1.count {
let value1 = str1[str1.index(str1.startIndex, offsetBy: index)]
let value2 = str2[str2.index(str2.startIndex, offsetBy: index)]
dictionary[value1] = (dictionary[value1] ?? 0) + 1
dictionary[value2] = (dictionary[value2] ?? 0) - 1
}
return !dictionary.contains(where: {(_, value) in
return value != 0
})
}
Time complexity - O(n)
// Make sure name your variables correctly so you won't confuse
// Mutate the constants parameter, lowercase to handle capital letters and the sorted them to compare both. Finally check is there are equal return true or false.
func anagram(str1: String, srt2: String)->Bool{
let string1 = str1.lowercased().sorted()
let string2 = srt2.lowercased().sorted()
if string1 == string2 {
return true
}
return false
}
// This answer also would work
// Convert your parameters on Array, then sorted them and compare them
func ana(str1: String, str2: String)->Bool{
let a = Array(str1)
let b = Array(str2)
if a.sorted() == b.sorted() {
return true
}
return false
}
Don't forget whitespaces
func isAnagram(_ stringOne: String, stringTwo: String) -> Bool {
return stringOne.lowercased().sorted().filter { $0 != " "} stringTwo.lowercased().sorted().filter { $0 != " "}
}
Swift 4.1 Function will give you 3 questions answer for Anagram :-
1. Input Strings (a,b) are Anagram ? //Bool
2. If not an Anagram then number of count require to change Characters in strings(a,b) to make them anagram ? // Int
3. If not an Anagram then list of Characters needs to be change in strings(a,b) to make them anagram ? // [Character]
STEP 1:- Copy and Paste below function in to your required class:-
//MARK:- Anagram checker
func anagramChecker(a:String,b:String) -> (Bool,Int,[Character]) {
var aCharacters = Array(a)
var bCharacters = Array(b)
var count = 0
var isAnagram = true
var replacementRequiredWords:[Character] = [Character]()
if aCharacters.count == bCharacters.count {
let listA = aCharacters.filter { !bCharacters.contains($0) }
for i in 0 ..< listA.count {
if !replacementRequiredWords.contains(listA[i]) {
count = count + 1
replacementRequiredWords.append(listA[i])
isAnagram = false
}
}
let listB = bCharacters.filter { !aCharacters.contains($0) }
for i in 0 ..< listB.count {
if !replacementRequiredWords.contains(listB[i]) {
count = count + 1
replacementRequiredWords.append(listB[i])
isAnagram = false
}
}
}else{
//cant be an anagram
count = -1
}
return (isAnagram,count,replacementRequiredWords)
}
STEP 2 :- Make two Input Strings for test
// Input Strings
var a = "aeb"
var b = "abs"
STEP 3:- Print results :-
print("isAnagram : \(isAnagram(a: a, b: b).0)")
print("number of count require to change strings in anagram : \(isAnagram(a: a, b: b).1)")//-1 will come in case of cant be a Anagram
print("list of Characters needs to be change : \(isAnagram(a: a, b: b).2)")
Results of above exercise:-
isAnagram : false
number of count require to change strings in anagram : 2
list of Characters needs to be change : ["e", "s"]
Hope this 10 minutes exercise will give some support to my Swift
family for solving Anagram related problems easily. :)
We can use dictionary to construct a new data structure container. Then compare the value by key/character of the string.
func anagram(str1: String, str2 : String) -> Bool {
var dict1 = [Character: Int]()
var dict2 = [Character:Int]()
for i in str1 {
if let count = dict1[i] {
dict1[i] = count + 1
} else {
dict1[i] = 1
}
}
for j in str2 {
if let count = dict2[j] {
dict2[j] = count + 1
} else {
dict2[j] = 1
}
}
return dict1 == dict2 ? true : false
}
// input -> "anna", "aann"
// The count will look like:
// ["a": 2, "n": 2] & ["a": 2, "n": 2]
// then return true
Another easy that I just realise doing an Anagram function in Swift 5.X
func checkForAnagram(firstString firstString: String, secondString: String) -> Bool {
return !firstString.isEmpty && firstString.sorted() == secondString.sorted()
}
class Solution {
func isAnagram(_ s: String, _ t: String) -> Bool {
guard s.count == t.count else { return false }
let dictS = s.reduce(into: [Character: Int]()) { $0[$1, default: 0] += 1 }
let dictT = t.reduce(into: [Character: Int]()) { $0[$1, default: 0] += 1 }
for letter in s {
if let count = dictS[letter] {
guard count == dictT[letter] else { return false }
}
}
return true
}
}
Check two strings are anagram using inout method in Swift
func checkAnagramString(str1: inout String, str2: inout String)-> Bool{
var result:Bool = false
str1 = str1.lowercased().trimmingCharacters(in: .whitespace)
str2 = str2.lowercased().trimmingCharacters(in: .whitespaces)
if (str1.count != str2.count) {
return result
}
for c in str1 {
if str2.contains(c){
result = true
}
else{
result = false
return result
}
}
return result
}
Call function to check strings are anagram or not
var str1 = "tommarvoloriddle"
var str2 = "iamlordvoldemort"
print(checkAnagramString(str1: &str1, str2: &str2)) //Output = true.
func isAnagram(word1: String, word2: String) -> Bool {
let set1 = Set(word1)
let set2 = Set(word2)
return set1 == set2
}
or
func isAnagram(word1: String,word2: String) -> Bool {
return word1.lowercased().sorted() == word2.lowercased().sorted()
}

Resources