I found some code to encode a Base10-String with to a custom BaseString:
func stringToCustomBase(encode: Int, alphabet: String) -> String {
var base = alphabet.count, int = encode, result = ""
repeat {
let index = alphabet.index(alphabet.startIndex, offsetBy: (int % base))
result = [alphabet[index]] + result
int /= base
} while (int > 0)
return result
}
... calling it with this lines:
let encoded = stringToCustomBase(encode: 9291, alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
print(encoded)
The encoding above works pretty good. But what about decoding the encoded string?
So because I got no idea how to decode a (in this case Base62 [alphabet.count=62]) to a human readable string (in this case [Base10]) any help would be super appreciated.
PS: (A full code solution is not required, I can also come up with some kind of pseudo-code or maybe just a few-lines of code)
This is what I've tried so far:
func reVal(num: Int) -> Character {
if (num >= 0 && num <= 9) {
return Character("\(num)")
}
return Character("\(num - 10)A");
}
func convertBack() {
var index = 0;
let encoded = "w2RDn3"
var decoded = [Character]()
var inputNum = encoded.count
repeat {
index+=1
decoded[index] = reVal(num: inputNum % 62)
//encoded[index] = reVal(inputNum % 62);
inputNum /= 62;
} while (inputNum > 0)
print(decoded);
}
Based on the original algorithm you need to iterate through each character of the encoded string, find the location of that character within the alphabet, and calculate the new result.
Here are both methods and some test code:
func stringToCustomBase(encode: Int, alphabet: String) -> String {
var base = alphabet.count, string = encode, result = ""
repeat {
let index = alphabet.index(alphabet.startIndex, offsetBy: (string % base))
result = [alphabet[index]] + result
string /= base
} while (string > 0)
return result
}
func customBaseToInt(encoded: String, alphabet: String) -> Int? {
let base = alphabet.count
var result = 0
for ch in encoded {
if let index = alphabet.index(of: ch) {
let mult = result.multipliedReportingOverflow(by: base)
if (mult.overflow) {
return nil
} else {
let add = mult.partialValue.addingReportingOverflow(alphabet.distance(from: alphabet.startIndex, to: index))
if (add.overflow) {
return nil
} else {
result = add.partialValue
}
}
} else {
return nil
}
}
return result
}
let startNum = 234567
let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let codedNum = stringToCustomBase(encode: startNum, alphabet: alphabet)
let origNun = customBaseToInt(encoded: codedNum, alphabet: alphabet)
I made the customBaseToInt method return an optional result in case there are characters in the encoded value that are not in the provided alphabet.
You can achieve this via reduce:
enum RadixDecodingError: Error {
case invalidCharacter
case overflowed
}
func customRadixToInt(str: String, alphabet: String) throws -> Int {
return try str.reduce(into: 0) {
guard let digitIndex = alphabet.index(of: $1) else {
throw RadixDecodingError.invalidCharacter
}
let multiplied = $0.multipliedReportingOverflow(by: alphabet.count)
guard !multiplied.overflow else {
throw RadixDecodingError.overflowed
}
let added = multiplied.partialValue.addingReportingOverflow(alphabet.distance(from: alphabet.startIndex, to: digitIndex))
guard !added.overflow else {
throw RadixDecodingError.overflowed
}
$0 = added.partialValue
}
}
I used the exception throwing mechanism so that the caller can distinguish between invalid characters or overflow errors.
Related
I'm was trying to convert hexString to Array of Bytes([UInt8]) I searched everywhere but couldn't find a solution. Below is my swift 2 code
func stringToBytes(_ string: String) -> [UInt8]? {
let chars = Array(string)
let length = chars.count
if length & 1 != 0 {
return nil
}
var bytes = [UInt8]()
bytes.reserveCapacity(length/2)
for var i = 0; i < length; i += 2 {
if let a = find(hexChars, chars[i]),
let b = find(hexChars, chars[i+1]) {
bytes.append(UInt8(a << 4) + UInt8(b))
} else {
return nil
}
}
return bytes
}
Example Hex
Hex : "7661706f72"
expectedOutput : "vapor"
This code can generate the same output as your swift 2 code.
func stringToBytes(_ string: String) -> [UInt8]? {
let length = string.characters.count
if length & 1 != 0 {
return nil
}
var bytes = [UInt8]()
bytes.reserveCapacity(length/2)
var index = string.startIndex
for _ in 0..<length/2 {
let nextIndex = string.index(index, offsetBy: 2)
if let b = UInt8(string[index..<nextIndex], radix: 16) {
bytes.append(b)
} else {
return nil
}
index = nextIndex
}
return bytes
}
let bytes = stringToBytes("7661706f72")
print(String(bytes: bytes!, encoding: .utf8)) //->Optional("vapor")
Here is a sketch of how I'd do it in a more idiomatic Swift style (this might be Swift 4 only):
func toPairsOfChars(pairs: [String], string: String) -> [String] {
if string.count == 0 {
return pairs
}
var pairsMod = pairs
pairsMod.append(String(string.prefix(2)))
return toPairsOfChars(pairs: pairsMod, string: String(string.dropFirst(2)))
}
func stringToBytes(_ string: String) -> [UInt8]? {
// omit error checking: remove '0x', make sure even, valid chars
let pairs = toPairsOfChars(pairs: [], string: string)
return pairs.map { UInt8($0, radix: 16)! }
}
Following code may be help for you
extension String {
/// Create `Data` from hexadecimal string representation
///
/// This takes a hexadecimal representation and creates a `Data` object. Note, if the string has any spaces or non-hex characters (e.g. starts with '<' and with a '>'), those are ignored and only hex characters are processed.
///
/// - returns: Data represented by this hexadecimal string.
func hexadecimal() -> Data? {
var data = Data(capacity: characters.count / 2)
let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
regex.enumerateMatches(in: self, options: [], range: NSMakeRange(0, characters.count)) { match, flags, stop in
let byteString = (self as NSString).substring(with: match!.range)
var num = UInt8(byteString, radix: 16)!
data.append(&num, count: 1)
}
guard data.count > 0 else {
return nil
}
return data
}
}
extension String {
/// Create `String` representation of `Data` created from hexadecimal string representation
///
/// This takes a hexadecimal representation and creates a String object from that. Note, if the string has any spaces, those are removed. Also if the string started with a `<` or ended with a `>`, those are removed, too.
init?(hexadecimal string: String) {
guard let data = string.hexadecimal() else {
return nil
}
self.init(data: data, encoding: .utf8)
}
/// - parameter encoding: The `NSStringCoding` that indicates how the string should be converted to `NSData` before performing the hexadecimal conversion.
/// - returns: `String` representation of this String object.
func hexadecimalString() -> String? {
return data(using: .utf8)?
.hexadecimal()
}
}
extension Data {
/// Create hexadecimal string representation of `Data` object.
/// - returns: `String` representation of this `Data` object.
func hexadecimal() -> String {
return map { String(format: "%02x", $0) }
.joined(separator: "")
}
}
Use like this :
let hexString = "68656c6c 6f2c2077 6f726c64"
print(String(hexadecimalString: hexString))
Or
let originalString = "hello, world"
print(originalString.hexadecimalString())
After lot searching and thinking here is how you do it
func toByteArray( _ hex:String ) -> [UInt8] {
// remove "-" from Hexadecimal
var hexString = hex.removeWord( "-" )
let size = hexString.characters.count / 2
var result:[UInt8] = [UInt8]( repeating: 0, count: size ) // array with length = size
// for ( int i = 0; i < hexString.length; i += 2 )
for i in stride( from: 0, to: hexString.characters.count, by: 2 ) {
let subHexStr = hexString.subString( i, length: 2 )
result[ i / 2 ] = UInt8( subHexStr, radix: 16 )! // ! - because could be null
}
return result
}
extension String {
func subString( _ from: Int, length: Int ) -> String {
let size = self.characters.count
let to = length + from
if from < 0 || to > size {
return ""
}
var result = ""
for ( idx, char ) in self.characters.enumerated() {
if idx >= from && idx < to {
result.append( char )
}
}
return result
}
func removeWord( _ word:String ) -> String {
var result = ""
let textCharArr = Array( self.characters )
let wordCharArr = Array( word.characters )
var possibleMatch = ""
var i = 0, j = 0
while i < textCharArr.count {
if textCharArr[ i ] == wordCharArr[ j ] {
if j == wordCharArr.count - 1 {
possibleMatch = ""
j = 0
}
else {
possibleMatch.append( textCharArr[ i ] )
j += 1
}
}
else {
result.append( possibleMatch )
possibleMatch = ""
if j == 0 {
result.append( textCharArr[ i ] )
}
else {
j = 0
i -= 1
}
}
i += 1
}
return result
}
}
Refer this video to know how I did it.
Credit : AllTech
Conversion of String to Data with nicer syntax.
static func hexStringToData(string: String) -> Data {
let stringArray = Array(string)
var data: Data = Data()
for i in stride(from: 0, to: string.count, by: 2) {
let pair: String = String(stringArray[i]) + String(stringArray[i+1])
if let byteNum = UInt8(pair, radix: 16) {
let byte = Data([byteNum])
data.append(byte)
}
else{
fatalError()
}
}
return data
}
extension String {
var masked: String {
// some logic which I have to write to mask string.
// I tried following and just shows x 🤦♂️
// replacingOccurrences(
// of: ".(.+).",
// with: "x",
// options: .regularExpression,
// range: nil
//)
}
}
let helloWorld = "Hello World"
print("Masked string is - \(helloWorld.masked)")
Expected output is - "Hxxxxxxxxxd"
There is a Regular Expression way with lookaround
extension String {
var masked: String {
replacingOccurrences(
of: "(?!^).(?!$)", // RegEx
with: "x", // Replacement
options: .regularExpression // Option to set RegEx
)
}
}
You can enumerate the string and apply map transform to get the expected output:
extension String {
var masked: String {
self.enumerated().map({ (index, ch) in
if index == 0
|| index == self.count - 1 {
return String(ch)
}
return "x"
}).joined()
}
}
let str = "hello"
print("after masking \(str.masked)") // Output - hxxxo
The map transform will return an array, so use joined() to convert the array back to String. Also, note that you have to typecast ch to String as String(ch) because the type of ch is 'String.Element' (aka 'Character').
extension Sequence {
func replacingEachInteriorElement(with replacement: Element) -> [Element] {
let prefix = dropLast()
return
prefix.prefix(1)
+ prefix.dropFirst().map { _ in replacement }
+ suffix(1)
}
}
extension String {
var masked: Self {
.init( replacingEachInteriorElement(with: "x") )
}
}
"Hello World".masked == "Hxxxxxxxxxd" // true
"H🦾👄🐺🥻🐸🦈🏄♂️🍯🪐d".masked == "Hello World".masked // true
"🥮".masked // 🥮
"🥶😎".masked // 🥶😎
[].replacingEachInteriorElement(with: 500) // []
My solution without using Regular Expression:
extension String {
var masked: String {
if self.count < 2 { return self }
var output = self
let range = self.index(after: self.startIndex)..<self.index(before: endIndex)
let replacement = String.init(repeating: "x", count: output.count - 2)
output.replaceSubrange(range, with: replacement)
return output
}
}
So far, I've found following solution.
extension String {
var masked: String {
var newString = ""
for index in 0..<count {
if index != 0 && index != count-1 {
newString.append(contentsOf: "x")
} else {
let array = Array(self)
let char = array[index]
let string = String(char)
newString.append(string)
}
}
return newString
}
}
If you want to leave first and last letters you can use this ->
public extension String {
var masked: String {
return prefix(1) + String(repeating: "x", count: Swift.max(0, count-2)) + suffix(1)
}
}
USAGE
let hello = "Hello"
hello.masked
// Hxxxo
OR
you can pass unmasked character count ->
public extension String {
func masked(with unmaskedCount: Int) -> String {
let unmaskedPrefix = unmaskedCount/2
return prefix(unmaskedPrefix) + String(repeating: "x", count: Swift.max(0, count-unmaskedPrefix)) + suffix(unmaskedPrefix)
}
}
USAGE
let hello = "Hello"
hello.masked(with: 2)
// Hxxxo
let number = "5555555555"
number.masked(with: 4)
// 55xxxxxx55
I've created a method which generates and returns a random string of both letters and numbers, but for some reason I only get a string with numbers and the length of the string doesn't come close to what I asked it to be. A few examples of strings that have been returned: "478388299949939566" (inserted 18 as the length), "3772919388584334" (inserted 9 as the length), "2293010089409293945" (inserted 6 as the length). Anyone can see what I'm missing here?
func generateRandomStringWithLength(length:Int) -> String {
let randomString:NSMutableString = NSMutableString(capacity: length)
let letters:NSMutableString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
for index in 0...length {
let randomIndex:Int = Int(arc4random_uniform(UInt32(62)))
randomString.append("\(letters.character(at: randomIndex))")
}
return String(randomString)
}
Your problem is here:
letters.character(at: randomIndex)
it's function returns the character at a given UTF-16 code unit index, not not just a character
Here is my version, I guess its more swiftly.
func generateRandomStringWithLength(length: Int) -> String {
var randomString = ""
let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
for _ in 1...length {
let randomIndex = Int(arc4random_uniform(UInt32(letters.characters.count)))
let a = letters.index(letters.startIndex, offsetBy: randomIndex)
randomString += String(letters[a])
}
return randomString
}
generateRandomStringWithLength(length: 5)
Use this:
func generateRandomStringWithLength(length:Int) -> String {
let randomString:NSMutableString = NSMutableString(capacity: length)
let letters:NSMutableString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
var i: Int = 0
while i < length {
let randomIndex:Int = Int(arc4random_uniform(UInt32(letters.length)))
randomString.appendString("\(Character( UnicodeScalar( letters.characterAtIndex(randomIndex))))")
i += 1
}
return String(randomString)
}
Calling generateRandomStringWithLength method:
print(generateRandomStringWithLength(5))
print(generateRandomStringWithLength(10))
print(generateRandomStringWithLength(20))
print(generateRandomStringWithLength(7))
print(generateRandomStringWithLength(14))
Sample Output:
GIrqb
nWmieQRVdk
r0It9V1xkGFRa2HVwtCw
RLIRuVI
nXnFGV2LQ3CjbD
I'm having difficulties implementing a function converting hex value(little endian) to decimal value.
So I'm writing function:
func convertHexLittleEndianToDeciaml(input:String) -> (int)
and Input is always 4 bytes(so 8 characters in input string)
value for convertHexLittleEndianToDeciaml("606d0000") should return 28,000
You can write something like this:
(See UPDATEs)
func convertHexLittleEndianToDeciaml(input:String) -> Int32 {
if let beValue = Int32(input, radix: 16) where input.characters.count == 8 {
return beValue.byteSwapped
} else {
//or `fatalError()` or `return 0` or ...
return Int32.min
}
}
print(convertHexLittleEndianToDeciaml("606d0000")) //->28000
UPDATE
Sorry, but the code above have some overflow issue, happens with something like "FF010000":
func convertHexLittleEndianToDeciaml(input:String) -> Int32 {
if let beValue = UInt32(input, radix: 16) where input.characters.count == 8 {
return Int32(bitPattern: beValue.byteSwapped)
} else {
//or `fatalError()` or `return 0` or ...
return Int32.min
}
}
UPDATE2
So, I have found that returning a valid Int32 in error case might cause a bug which cannot easily be found. I recommend you to change the return type to Optional and return nil in error case.
func convertHexLittleEndianToDeciaml(input:String) -> Int32? {
guard let beValue = UInt32(input, radix: 16) where input.characters.count == 8 else {
return nil
}
return Int32(bitPattern: beValue.byteSwapped)
}
if let value = convertHexLittleEndianToDeciaml("606d0000") {
print(value) //->28000
} else {
print("Hex format invalid")
}
Here's a solution that works for longer numbers that I wrote:
func convert(number: String) -> Int {
var formatted = number
if number.count <= 16 {
let difference = 16 - number.count
for _ in 0..<difference {
formatted.append("0")
}
} else {
return 0
}
let value = UInt64(formatted, radix: 16) ?? 0
let z = value.byteSwapped
let final = UInt64(bitPattern: Int64(z))
return Int(final)
}
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()
}