無限大な夢のあと

テニスとアニメが大好きな厨二病SEのブログ

Swiftで言語処理100本ノック #1 00. 文字列の逆順 ~ 02. 文字列の交互の結合

try!Swiftに参加して、iOS開発/Swiftのモチベーションが高くなっている嶽です。
今回、せっかく問題を解いたのでブログにアウトプットしようと記事を書きました。

この度、今月の3連休(3/18(土)-3/20(月・祝))に、会社の仲間と開発合宿に行かせて頂けることになり、その中でサーバーサイドSwiftをRaspberry Pi上で動かしてアプリを作ることになりました。
ただ、私自身、業務でiOS開発に入って間もないので、Swiftにはまだ全然慣れていません。
サーバーサイドの処理を書くにあたって、一般的なプログラミング言語の処理に慣れるためにSwiftで次の言語処理100本ノックで問題を解いていくことにしました。
www.cl.ecei.tohoku.ac.jp

今回は、次の3問を解きたいと思います。

  1. 00. 文字列の逆順
  2. 01. 文字列の奇数番目を取り出し、文字列を連結。
  3. 02. 文字列の交互の結合

基本は慣れるのが目的でもあるので、計算量が多いとわかっていても簡潔に書ける方法で問題を解いていきたいと思います。

00. 文字列の逆順
文字列"stressed"の文字を逆に(末尾から先頭に向かって)並べた文字列を得よ.

回答は以下になります。

print(String("stressed".characters.reversed()))
///実行結果 
desserts

以下、簡単な解説です。
処理的には文字列から個々の文字の配列にして逆順にできると良いので、そのような処理はString.charactersが使えそうでした。
String.charactersについて、よく知らなかったので次の書籍で調べました。

Swift実践入門 ── 直感的な文法と安全性を兼ね備えた言語 (WEB+DB PRESS plus)

Swift実践入門 ── 直感的な文法と安全性を兼ね備えた言語 (WEB+DB PRESS plus)

書籍内では次のように解説されています。

/// 実践Swift 40ページ以降
/// 2.6 String型 文字列を表す型

/// 文字列を表すリテラルを文字列リテラルと言い、"abc" のように "(ダブル クオート)で文字列を囲むと文字列リテラルと解釈されます。
/// 文字列リテラル は、文字列を表す String 型や、後述する文字を表す Character 型の値を生成 します。

/// String 型の個々の文字は Character 型で表され、Character 型の集まりは String.CharacterView 型で表されます。
String.CharacterView 型は、Character 型のコレクションを表す型です。コ レクションとはデータの集まりをまとめて格納するデータ構造で、要素の列挙や要素数のカウントなどの機能を持ちます。後述する配列や辞書もコレクションです。

01. 「パタトクカシーー」
「パタトクカシーー」という文字列の1,3,5,7文字目を取り出して連結した文字列を得よ.

回答は以下になります。

print(String("パタトクカシーー".characters.enumerated().filter { $0.0 % 2 == 0 }.map { $0.1 }))
///実行結果 
パトカー

以下、簡単な解説です。
charactersについて、enumratedメソッドを使うと、Tupleを作成できるようです。
以下、Swiftのコード内のコメント。

/// enumeratedのドキュメント
/// Returns a sequence of pairs (*n*, *x*), where *n* represents a
/// consecutive integer starting at zero, and *x* represents an element of
/// the sequence.
///
/// This example enumerates the characters of the string "Swift" and prints
/// each character along with its place in the string.
///
/// for (n, c) in "Swift".characters.enumerated() {
/// print("\(n): '\(c)'")
/// }
/// // Prints "0: 'S'"
/// // Prints "1: 'w'"
/// // Prints "2: 'i'"
/// // Prints "3: 'f'"
/// // Prints "4: 't'"
///

処理としては、個々の文字の配列にして、配列の添字の数を2で割って余りが0の場合の文字列を連結する処理をできれば良いです。
今回はfileterメソッドを使い、使用する文字列を決めて、最後に連結する処理にしました。
filterメソッド内では$0.0は各要素の添字のindex、にアクセスできます。
最後にmapメソッドで受け取ったtupleの文字に$0.1でアクセスできるので、その結果を全体でStringでキャストして、文字列にしています。

02. 「パトカー」+「タクシー」=「パタトクカシーー」
「パトカー」+「タクシー」の文字を先頭から交互に連結して文字列「パタトクカシーー」を得よ.

回答は以下になります。

let patrolCar = "パトカー".characters.map { String($0) }
let taxi = "タクシー".characters.map { String($0) 
print(zip(patrolCar, taxi).reduce("") { $0 + $1.0 + $1.1 })
///実行結果 
パタトクカシーー

以下、簡単な解説です。
まず、後処理でzipメソッドを使いたかったため、「パトカー」と「タクシー」をStringの配列にします。
Character(文字)の配列ではなく、String(文字列)の配列なのはStringクラスに準備されている+メソッドで文字列連結をさせるためです。
その後に、zipメソッドとreduceメソッドを使って、文字列を連結させていきます。
zipメソッドは今回のような用途で使える便利なメソッドです。
zipメソッドを使うと次のような型のデータに変換されます。

/// zipした後の型はZip2Sequence<Array<String>, Array<String>>
/// (_sequence1: ["パ", "ト", "カ", "ー"], _sequence2: ["タ", "ク", "シ", "ー"])

上記のデータをreduceメソッドを使って文字列連結をしていきます。
reduceメソッドは次のように動作します。

初期値は設定している""(空文字)です。
$0は持ち越してくる値になります。
初回は、$0が"" $1は("パ","タ")のTuple $1.0がパ、$1.1がタ
2回目回は、$0が"パタ" $1.0がト、$1.1がク
3回目回は、以下略

もし、こんな処理だともっと簡潔に書けるよーというのがありましたら、ぜひ教えて頂けると嬉しいです。


TECHNICAL MASTER はじめてのiOSアプリ開発 Xcode8+Swift3対応

TECHNICAL MASTER はじめてのiOSアプリ開発 Xcode8+Swift3対応

Functional Swift: Updated for Swift 3

Functional Swift: Updated for Swift 3