5

I am trying to cycle through the entire alphabet using Swift. The only problem is that I would like to assign values to each letter.

For Example: a = 1, b = 2, c = 3 and so on until I get to z which would = 26.

How do I go through each letter in the text field that the user typed while using the values previously assigned to the letters in the alphabet?

After this is done, how would I add up all the letters values to get a sum for the entire word. I am looking for the simplest possible way to accomplish this but works the way I would like it to.

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
Bigfoot11
  • 911
  • 2
  • 11
  • 25
  • i think this is something to get you in the right direction: http://stackoverflow.com/a/24102584/421755 – Simon Mar 05 '15 at 22:41

5 Answers5

7

edit/update: Xcode 12.5 • Swift 5.4


extension Character {
    static let alphabetValue = zip("abcdefghijklmnopqrstuvwxyz", 1...26).reduce(into: [:]) { $0[$1.0] = $1.1 }
    var lowercased: Character { .init(lowercased()) }
    var letterValue: Int? { Self.alphabetValue[lowercased] }
}

extension String {
    var wordValue: Int { compactMap(\.letterValue).reduce(0, +) }
}

Character("A").letterValue    // 1
Character("b").letterValue    // 2
Character("c").letterValue    // 3
Character("d").letterValue    // 4
Character("e").letterValue    // 5
Character("Z").letterValue    // 26
"Abcde".wordValue    // 15
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • 1
    I was trying to work out how to do this with the index of the array. But the range location of the word is a better approach. – Fogmeister Mar 05 '15 at 22:49
  • 2
    @Buster he is changing the letters to lowercase before checking so yes. – Fogmeister Mar 05 '15 at 22:52
  • How would I display this sum in a UILabel. – Bigfoot11 Mar 05 '15 at 22:59
  • You need to connect a editing changed sent action to an ibaction where you can loop trough the letters and sum its values. – Leo Dabus Mar 05 '15 at 23:11
  • When I created the IBAction the error "Declaration is only valid at file scope" on the extension String { line. Do you want me to post the code I have as of now to see if you see any problems with it that I don't see – Bigfoot11 Mar 05 '15 at 23:26
  • Just add a new file to your project (File > New > File > iOS Source Swift File ) call it main.swift and add those extensions there. You can also put them at the bottom of your view controller. – Leo Dabus Mar 05 '15 at 23:29
  • I dont understand this at all. I need to be able to know what this means so i can fix it if I want to change anything. This is very confusing. – Bigfoot11 Apr 08 '15 at 18:52
  • What part you don't understand ? You just need to open your project add a new file (iOS Swift sourced file. Change the import Foundation to import UIKit and place those extensions there. – Leo Dabus Apr 08 '15 at 19:50
  • What it does it creates an array of characters for any string in this case an alphabet and try to find the letter. If found it returns the letter position which you can use as the index to extract the letter value. – Leo Dabus Apr 08 '15 at 19:52
  • Btw it is all in a single line I can't understand what part is so confusing – Leo Dabus Apr 08 '15 at 19:53
  • The only thing you may have difficult to understand is the currying I use to find out the wordValue but I think the naming I choose is self explanatory – Leo Dabus Apr 08 '15 at 19:55
  • If you post a github or your project folder zipped I can fix it for you – Leo Dabus Apr 08 '15 at 19:57
  • I dont understand the extensions part. What is the point of it? Why do I need it? Can't I just put in the file I already have – Bigfoot11 Apr 08 '15 at 20:40
  • You don't I will post it as a regular function for you – Leo Dabus Apr 08 '15 at 20:44
  • I just don't understand what the difference is between an extension and a regular function. – Bigfoot11 Apr 08 '15 at 20:49
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/74755/discussion-between-buster-and-leonardo-savio-dabus). – Bigfoot11 Apr 08 '15 at 20:52
0

I'd create a function something like this...

func valueOfLetter(inputLetter: String) -> Int {
    let alphabet = ["a", "b", "c", "d", ... , "y", "z"] // finish the array properly

    for (index, letter) in alphabet {
        if letter = inputLetter.lowercaseString {
            return index + 1
        }
    }

    return 0
}

Then you can iterate the word...

let word = "hello"
var score = 0

for character in word {
    score += valueOfLetter(character)
}
Fogmeister
  • 76,236
  • 42
  • 207
  • 306
  • There is an error saying: 'String' is not convertible to '([String], [String]) – Bigfoot11 Mar 12 '15 at 10:20
  • Ah, sorry I used the wrong enumeration method for getting the index, value tuple. I can't look now but if you search google for swift array you'll find the right method. – Fogmeister Mar 12 '15 at 11:21
0

Assign the letters by iterating over them and building a dictionary with letters corresponding to their respective values:

let alphabet: [String] = [
    "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
]

var alphaDictionary = [String: Int]()
var i: Int = 0

for a in alphabet {
    alphaDictionary[a] = ++i
}

Use Swift's built-in Array reduce function to sum up the letters returned from your UITextViewDelegate:

func textViewDidEndEditing(textView: UITextView) {
    let sum = Array(textView.text.unicodeScalars).reduce(0) { a, b in
        var sum = a

        if let d = alphaDictionary[String(b).lowercaseString] {
            sum += d
        }

        return sum
    }
}
kellanburket
  • 12,250
  • 3
  • 46
  • 73
0

Maybe you are looking for something like this:

func alphabetSum(text: String) -> Int {
    let lowerCase = UnicodeScalar("a")..."z"
    return reduce(filter(text.lowercaseString.unicodeScalars, { lowerCase ~= $0}), 0) { acc, x in
        acc + Int((x.value - 96))
    }
}


alphabetSum("Az") // 27 case insensitive
alphabetSum("Hello World!") // 124 excludes non a...z characters

The sequence text.lowercaseString.unicodeScalars ( lower case text as unicode scalar ) is filtered filter keeping only the scalars that pattern match ~= with the lowerCase range. reduce sums all the filtered scalar values shifted by -96 (such that 'a' gives 1 etc.). reduce starts from an accumulator (acc) value of 0. In this solution the pattern match operator will just check for the scalar value to be between lowerCase.start (a) and lowerCase.end (z), thus there is no lookup or looping into an array of characters.

Matteo Piombo
  • 6,688
  • 2
  • 25
  • 25
0

I've just put together the following function in swiftstub.com and it seems to work as expected.

func getCount(word: String) -> Int {
    let alphabetArray = Array(" abcdefghijklmnopqrstuvwxyz")
    var count = 0

    // enumerate through each character in the word (as lowercase)
    for (index, value) in enumerate(word.lowercaseString) {
        // get the index from the alphabetArray and add it to the count
        if let alphabetIndex = find(alphabetArray, value) {
            count += alphabetIndex
        }
    }

    return count
}

let word = "Hello World"
let expected = 8+5+12+12+15+23+15+18+12+4

println("'\(word)' should equal \(expected), it is \(getCount(word))")

// 'Hello World' should equal 124 :)

The function loops through each character in the string you pass into it, and uses the find function to check if the character (value) exists in the sequence (alphabetArray), and if it does it returns the index from the sequence. The index is then added to the count and when all characters have been checked the count is returned.

ubersnack
  • 512
  • 6
  • 19