Markus
Markus

Reputation: 33

Counting different Characters in Swift

I am new to swift and I am trying to count the different characters in a string but my code returns the value for the whole String

for example:

var string aString = "aabb"
aString.characters.count()             //returns 5

counter = 0
let a = "a"

for a in aString.characters {
  counter++
}                                      //equally returns 5

Can somebody explain why this is happening and how I could count the different chars?

Upvotes: 0

Views: 17406

Answers (8)

Ullas Pujary
Ullas Pujary

Reputation: 359

func repeatedCharaterPrint(inputArray: [String]) -> [String:Int] {
var dict = [String:Int]()
if inputArray.count > 0 {
    for char in inputArray {
        if let keyExists = dict[char], keyExists != nil {
            dict[char] = Int(dict[char] ?? 0) + 1
        }else {
            dict[char] = 1
        }
    }
}
return dict

}

let aa = ["a","s","f","s","l","s"]
print(repeatedCharaterPrint(inputArray: aa))
//Answer : "["s": 3, "l": 1, "a": 1, "f": 1]"

Upvotes: 0

Dinu
Dinu

Reputation: 49

Construct a dictionary out of a sequence of (key, value) pairs. If we can guarantee that the keys are unique, we can use Dictionary(uniqueKeysWithValues:).

func characterFrequencies(of string: String) -> Dictionary<String.Element, Int> {
    let frequencyPair = string.map { ($0, 1) }
    return Dictionary(frequencyPair, uniquingKeysWith: +)
}

Usage : print(characterFrequencies(of: "Happy")) Result : ["a": 1, "H": 1, "y": 1, "p": 2]

Upvotes: 0

Dipak
Dipak

Reputation: 2433

Updated @Luca Angeletti's answer for Swift5.3 because characters property is unavailable in newer swift version.

var word = "aabb"

let numberOfChars = word.count // 4
let numberOfDistinctChars = Set(word).count // 2
let occurrenciesOfA = word.filter { $0 == "A" }.count // 0
let occurrenciesOfa = word.filter { $0 == "a" }.count // 2
let occurrenciesOfACaseInsensitive = word.filter { $0 == "A" || $0 == "a" }.count // 2

print(numberOfChars)
print(numberOfDistinctChars)
print(occurrenciesOfA)
print(occurrenciesOfa)
print(occurrenciesOfACaseInsensitive)

Upvotes: 0

Jerome Li
Jerome Li

Reputation: 1586

The characters property is deprecated, you can use components(separatedBy:) to find how many characters in a String. eg,

extension String {

    public func numberOfOccurrences(_ string: String) -> Int {
        return components(separatedBy: string).count - 1
    }

}
let aString = "aabbaa"
let aCount = aString.numberOfOccurrences("a") // aCount = 4

Upvotes: 1

sulabh
sulabh

Reputation: 249

This solution is written using hash function , so computation time would be O(1). good for long strings.

//Extension On String and Characters to get Ascii values and Char from Ascii

extension Character {
    //Get Ascii Value of Char
    var asciiValue:UInt32? {
        return String(self).unicodeScalars.filter{$0.isASCII}.first?.value
    }
}

extension String {
    //Char Char from Ascii Value
    init(unicodeScalar: UnicodeScalar) {
        self.init(Character(unicodeScalar))
    }


init?(unicodeCodepoint: Int) {
    if let unicodeScalar = UnicodeScalar(unicodeCodepoint) {
        self.init(unicodeScalar: unicodeScalar)
    } else {
        return nil
    }
}


static func +(lhs: String, rhs: Int) -> String {
    return lhs + String(unicodeCodepoint: rhs)!
}


static func +=(lhs: inout String, rhs: Int) {
    lhs = lhs + rhs
}
}

extension String {
    ///Get Char at Index from String
    var length: Int {
        return self.characters.count
    }

subscript (i: Int) -> String {
    return self[Range(i ..< i + 1)]
}

func substring(from: Int) -> String {
    return self[Range(min(from, length) ..< length)]
}

func substring(to: Int) -> String {
    return self[Range(0 ..< max(0, to))]
}

subscript (r: Range<Int>) -> String {
    let range = Range(uncheckedBounds: (lower: max(0, min(length, r.lowerBound)),
                                        upper: min(length, max(0, r.upperBound))))
    let start = index(startIndex, offsetBy: range.lowerBound)
    let end = index(start, offsetBy: range.upperBound - range.lowerBound)
    return self[Range(start ..< end)]
}

}

//Program :

let  strk = "aacncjkvkevkklvkdsjkbvjsdbvjkbsdjkvbjdsbvjkbsvbkjwlnkneilhfleknkeiohlgblehgilkbskdbvjdsbvjkdsbvbbvsbdvjlbsdvjbvjkdbvbsjdbjsbvjbdjbjbjkbjkvbjkbdvjbdjkvbjdbvjdbvjbvjdsbjkvbdsjvbkjsbvadvbjkenevknkenvnekvjksbdjvbjkbjbvbkjvbjdsbvjkbdskjvbdsbvjkdsbkvbsdkjbvkjsbvjsbdjkvbdsbvjkbdsvjbdefghaj"

print(strk)

//Declare array of fixes size 26 (characters) or you can say it as a hash table 
var freq = [Int](repeatElement(0, count: 26))

func hashFunc(char : Character) -> UInt32 {
    guard let ascii = char.asciiValue else {
        return 0
    }
    return ascii - 97 //97 used for ascii value of a
}


func countFre(string:String) {

    for i in 0 ... string.characters.count-1 {
        let charAtIndex = string[i].characters.first!
        let index = hashFunc(char: charAtIndex)
        let currentVal = freq[Int(index)]
        freq[Int(index)] = currentVal + 1
        //print("CurrentVal of \(charAtIndex) with index \(index) is \(currentVal)")

    }

    for charIndex in 0 ..< 26 {
        print(String(unicodeCodepoint: charIndex+97)!,freq[charIndex])
    }
}

countFre(string: strk)

Upvotes: -1

Luca Angeletti
Luca Angeletti

Reputation: 59506

It looks there is some confusion about what you really need.

I tried to answer to the 5 most likely interpretations.

var word = "aabb"

let numberOfChars = word.characters.count // 4
let numberOfDistinctChars = Set(word.characters).count // 2
let occurrenciesOfA = word.characters.filter { $0 == "A" }.count // 0
let occurrenciesOfa = word.characters.filter { $0 == "a" }.count // 2
let occurrenciesOfACaseInsensitive = word.characters.filter { $0 == "A" || $0 == "a" }.count // 2

print(occurrenciesOfA)
print(occurrenciesOfa)
print(occurrenciesOfACaseInsensitive)

Upvotes: 19

user3441734
user3441734

Reputation: 17544

check this

var aString = "aabb"
aString.characters.count // 4

var counter = 0
let a = "a" // you newer use this in your code 

for thisIsSingleCharacterInStringCharactersView in aString.characters {
    counter++
}
print(counter) // 4

it simply increase your counter for each character

to calculate number of different characters in you string, you probably can use something 'more advanced', like in next example

let str = "aabbcsdfaewdsrsfdeewraewd"

let dict = str.characters.reduce([:]) { (d, c) -> Dictionary<Character,Int> in
    var d = d
    let i = d[c] ?? 0
    d[c] = i+1
    return d
}
print(dict) // ["b": 2, "a": 4, "w": 3, "r": 2, "c": 1, "s": 3, "f": 2, "e": 4, "d": 4]

Upvotes: 13

luk2302
luk2302

Reputation: 57124

You code is quite faulty: it should probably start with

let aString = "aabb"

The solutions is to get the characters, put them into a set (unique) and then counting the members of the set:

let differentChars = Set(aString.characters).count

Correctly returns

2

Upvotes: 3

Related Questions