Swiftの基礎

import UIKit

// コメント
/*
 複数行
 コメント
*/

// 整数型
var i: Int = 123

// 浮動小数点型(倍精度)
var d: Double = 3.14

// 浮動小数点型(単精度)
var f: Float = 3.14

// 論理型
var flag : Bool = false
flag = true

// 文字列型
var s: String = "abc"

// 変数 (値を何度でも変更できる)
var a = 123
a = 456

// 定数 (いったん値を定義したら、その後変更できない)
let c1 = 42
//c1 = 1   // エラー

// セミコロンは複数行を1行につなげる時に使う。通常は必要なし
var a1 = 123; var a2 = 456

// 型の自動推論 (代入する値によって型が自動的に推論される)
let d1 = 70.0 // 右辺にDouble型のデータを書いたので、d1の型は自動的にDoubleと推論される。

// 変数の型を明示的に指定
let d2: Double = 70 // Intの70を与えているが、Doubleの70.0に変換される

let e1 = 94   // e1にはInt型の94が入る

//print("e1: " + e1)  // "e1: "はString型、e1はInt型。型が異なるのでエラー。

// StringとStringを結合
print("e1: " + String(e1))

// C言語風にフォーマットを指定して表示
print( String(format: "%d %5.3f", 123, 3.14159) )

// 改行なしのprint
print("abc", terminator:"")
print("ABC", terminator:"")

// 文字列の結合
var name = "Swift" + " " + "Programming"
name += " Language"

//文字数のカウント
//name.characters.count  -> obsolete
name.count

// printの文字列中で表示する変数を指定
let boyCount = 3
let girlCount = 5
print("There are \(boyCount) boys.")
print("There are \(girlCount) girls.")

// 配列
var colors : [String] = ["red", "black", "white", "blue"] // 要素の型を[]で囲う。
// var colors = ["red", "black", "white", "blue"]    と書いても同じ

// 配列要素を添字により参照
colors[0] = "pink"
colors[1] = "pink"

// 空の配列 例:String型を入れる空の配列
colors = [String]()

// 配列要素の追加
colors.append("red")
colors.append("black")
colors.append("white")
colors.append("blue")

// 配列要素の削除
colors.remove(at: 2) // colors[2]が削除される
colors.removeAll()   // 要素を全て削除

// 配列の要素数
colors.count

// 配列の要素をスキャンして処理
for c in colors {  // スキャン中の要素はcに入る。
    print(c)
}

// 多重配列
var array: [[Int]] = [[1,2,3],[4,5,6],[7,8,9]]
array[0][0]
array[2][1]

// ディクショナリ型
// キーと値のペアが格納される。キーを与えると、対応する値が検索される。
var petCounts = ["dog": 2, "cat": 3]
petCounts["dog"]
petCounts["cat"]
petCounts["dog"] = 123
petCounts["dog"]

// ディクショナリ型の要素数
petCounts.count

// キーをリストアップ
for k in petCounts.keys {
    print("key = " + k)
}

// 値をリストアップ
for v in petCounts.values {
    print("value = " + String(v))
}

// キーと値をリストアップ
for (pet, count) in petCounts {
    print(pet + ":" + String(count))
}

// 以下のようにしてもディクショナリを宣言できる。
var wordCounts = Dictionary<String, Int>()
wordCounts["apple"] = 10
wordCounts["apple"]

// 関数

// 例 Intを2個受け取り、Intを1個返す関数
func add(a: Int, b: Int) -> Int {
    return a + b 
}

// 関数呼び出し。引数のラベルを指定する必要がある。
add(a: 1, b: 2)

// 例: 整数nまでの総和を求める。
func sum(n: Int) -> Int {
    var s = 0
    for i in 0...n { // nを含む
        s += i
    }
    return s
}

// 関数呼び出し
sum(n: 10)

// 例: 再帰呼び出し
func recursiveSum(n: Int) -> Int {
    if n == 0 {
        return 0
    } else {
        return n + recursiveSum(n: n - 1)
    }
} 

recursiveSum(n: 10)

// 例: フィボナッチ数列
func fibonacci(n: Int) -> Int {
    switch (n) {
    case 1:
        return 1
    case 2:
        return 1
    default:
        return fibonacci(n: n-2) + fibonacci(n: n-1)
    }
}

// フィボナッチ数列を10項まで表示
for i in 1...10 {
    print(fibonacci(n: i))
}



func rank(score: Double) -> String {
    if score > 90 {   // if (score > 90) { ... のようにカッコを書いても良い
        return "A"
    } else if score > 70 {
        return "B"
    } else {
        return "C"
    }
}

let score = 99
score > 90 ? "OK" : "NG"  // 3項演算子。score>90が成立すれば"OK", 偽なら"NG"となる。


// 例: Stringを2個受け取り、Stringを1個返す関数
func createMessage(title: String, body: String) -> String {
    return "title: \(title)\nbody: \(body)"
}

// 関数呼び出し
createMessage(title: "task", body: "mail John")


// 関数
func createMessage(optionalTitle: String?, optionalContent: String?) -> String? {
    var message = ""
    if (optionalTitle != nil) {
        message += "title: " + optionalTitle! + "\n"
    }
    if let content = optionalContent {
        message += "content: " + content
    }
    
    if message == "" {
        return nil
    } else {
        return message
    }
}

func messageCount(optionalMessages: Array?) -> Int? {
    return optionalMessages?.count
}

func lastItem(items: Array?) -> Int? {
    return items?[items!.count - 1]
}


func evaluate(diff: Int) -> String? {
    switch diff  {
    case 100:
        return "max"
    case let x where 0 < x && x < 100:
        return "up"
    case 0:
        return "-"
    case let x where x < 0:
        return "down"
    default:
        return nil
    }
}

evaluate(diff: 56)

// 以下の文法は廃止された。
// var sum = 0
// for var i = 0; i < 3; ++i {
//     sum += i
// }

var sum = 0
for i in 0..<3 {  // 3 を含まない (0, 1, 2)
    print(i)
    sum += i
}
sum

sum = 0
for i in 0...3 {  // 3を含む (0, 1, 2, 3)
    print(i)
    sum += i
}
sum

// while ループ
var x = 1
while x < 100 {
    x = x * 2
}

// repeat..whileループ

var y = 1
repeat {
    y = y * 2
} while y < 100

// do..while は廃止された。
//var y = 2
//do {
//    y = y * 2
//} while y < 100

// タプルを返す
func getProfile() -> (name: String, age: Int, size: Double) {
    return ("Steve", 46, 8.9)
}
let profile = getProfile()
print("name: " + profile.name)


// 可変個の引数
func squareSum(numbers: Int...) -> Int {
    var sum = 0
    func addSquare(x: Int) {
        sum += x * x
    }
    for number in numbers {
        addSquare(x: number)
    }
    return sum
}

squareSum(numbers: 4, 6, 8, 9)


// nを与えると、nより大きい場合にtrueを返す関数を返す
func greaterThanN(n: Int) -> ((Int) -> Bool) { // 1つの引数の場合は(Int)のように()が必要になった。
    func gt(x: Int) -> Bool {
        return n < x
    }
    return gt
}

// Intに関する条件とIntの配列を与えると、条件を満たす最初のIntを返す
func get1st(condition: ((Int) -> Bool), targets: [Int]) -> Int? {
    for item in targets {
        if condition(item) {
            return item
        }
    }
    return nil
}

let greaterThan5 = greaterThanN(n: 5)
let a3 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
get1st(condition: greaterThan5, targets: a3)


// クロージャ

// Int型のxをとり、2*x を返すクロージャとして返す。
var c = {(x:Int) -> Int in return 2*x}
c(123) // 関数呼び出し

// 次のようにも書ける。
// 1文の場合は、その値が返り値となる(returnを書く必要がない)。
c = {(x:Int) -> Int in 2*x}
c(123)

// $番号で引数を指定できる。
// "2"と書くことで$0と戻り値の型がIntであることが推論される。
c = {2 * $0}


// mapは配列に対し、その要素のそれぞれに、クロージャで指定される処理を適用する。

// 配列の値をそれぞれ2乗し、新たな配列を返す。
let numbers = [1,2,3,4]
numbers.map({
    (x: Int) -> Int in
    return x*x
})

// 配列の値にそれぞれ3をかけ、新たな配列を返す。
numbers.map({
    n in 3*n
})

// 総和を求める。
// reduce(0)は和の初期値。$0はそれまでの累積値を表し、$1がスキャン中の要素を表す。
numbers.reduce(0) {
    $0 + $1
}

// ソート (昇順)   新しい配列が返される。
var b = [1, 5, 3, 12, 2]
b.sort()

// ソート (昇順)
var b2 = b.sorted(by: {$0 < $1})
b2

// ソート (降順)
var b3 = b.sorted(by: {$1 < $0})
b2

// in-placeソート (元の配列の要素が変更を受ける)
b.sort{$0 < $1}
b

// 逆転
b.reverse()

// 値が配列に含まれているかをチェック。含まれていればtrueを返す。
b.contains(3)

// 検索
// 指定した値が配列内に見つかればインデックスを返す。
var k:Int?  // オプショナル型。
k = b.firstIndex(of: 3)       // 値3のインデックス2が値となる。
k = b.firstIndex(of: 1000)  // 値1000は存在しないので、nilとなる。

2019.10.27