配列を操作する

投稿者: | 2017年1月30日

さて、乱数を生成するで作ろうとしているプログラムですが、Githubにあるスクリプトのように使用可能な文字種を選択できるようにします。

そうなるとASCII codeが連続しない場合があり得るので、使用可能な文字種を配列で指定して、配列の要素数に対して乱数を発生するように仕様を変えましょう。

簡単な配列の操作

ずいぶん以前に文法まとめのところで配列の紹介をしていますが、もう少しきちんと書きましょうか。

配列定義
変数ならvar、定数ならletに続けて配列名を宣言します。配列要素の型を[]で括って、:で配列名に続けます。配列要素そのものも[]で括り,で区切って初期化します。

let number: [String] = ["0","1","2","3","4","5","6","7","8","9"]
var member: [String] = []

配列要素を指定せずに配列宣言すると空の配列が定義されます。

配列要素の追加と削除
xオプションを与えられた時、紛らわしい文字を使用しない仕様なので状況に応じて配列要素を削除しなくてはいけません。

var number: [String] = ["0","1","2","3","4","5","6","7","8","9"]
number.remove(at:0)    // ["1","2","3","4","5","6","7","8","9"]
number.remove(at:1)    // ["1","3","4","5","6","7","8","9"]

この場合、配列要素の削除という配列そのものの変更が生じるのでvarで宣言する必要があります。要素の削除はremoveメソッドで要素番号を指定して削除します。削除後は番号が振り直されるので複数要素の削除は順番に注意が必要です。

逆に追加したいときはappendメソッドで要素を指定して追加します。

number.append("A")    //["1","3","4","5","6","7","8","9","A"]
配列の複製と結合
普通に代入すればOKです。numberの内容がmemberに複製されました。お互いに独立なので、複製後にnumberの内容を変更してもmemberの内容は変わりません。

var member:[String]
var number: [String] = ["0","1","2","3","4","5","6","7","8","9"]
member = number    // ["0","1","2","3","4","5","6","7","8","9"]

複数の配列を加算して代入すると結合された状態の配列が生成されます。

var member:[String]
var number: [String] = ["0","1","2"]
var upper: [String] = ["A","B","C"]
member = number + upper    // ["0","1","2","A","B","C"]
配列の要素数
配列の要素数はcountメソッドで取り出せます。

var number: [String] = ["0","1","2","3","4","5","6","7","8","9"]
print(number.count)    // 10

オプションに応じた配列を生成してみる

上記を踏まえまして、使用可能な文字種ごとの配列生成方法を考えてみます。

対象となる文字コードの範囲とともに、除外文字がある場合はその配列要素番号を降順で与えることにしましょう。このクラスは文字の配列を返します。

class GenerateMember {
  private var range: [[Int]]    // 対象文字種のASCII code開始番号と終了番号組み合わせ配列の配列で指定
  private var exclude: [Int]    // 配列から除外する文字の要素番号を降順で指定
  private var member: [String]  // 生成された対象文字の配列
  init(range: [[Int]] = [[]], exclude: [Int] = [], member: [String] = []) {
    self.range = range
    self.exclude = exclude
    self.member = member
  }
  func getMember(range: [[Int]], exclude: [Int]) -> ([String]) {
    for loop in range {
      for code in loop[0]...loop[1] {
        member.append("\(UnicodeScalar(code)!)")
      }
    }
    if exclude.count != 0 {
      for code in exclude {
        member.remove(at:code)
      }
    }
    return (member)
  }
}

テストコードを書く

テストコードは大英字、小英字、数字、記号のそれぞれについて、除外文字有り無しの8パターンを確認します。

#! /usr/bin/swift
import Foundation
let testCase: [(condition: String, range: [[Int]], exclude: [Int], result: [String])] =
  [("Alphabet upper case, full set.", [[65,90]], [], ["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"]),
  ("Alphabet upper case, excluded.", [[65,90]], [14,8], ["A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]),
  ("Alphabet lower case, full set.", [[97,122]], [], ["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"]),
  ("Alphabet lower case, excluded.", [[97,122]], [11], ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]),
  ("Number, full set.", [[48,57]], [], ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]),
  ("Number, excluded.", [[48,57]], [1,0], ["2", "3", "4", "5", "6", "7", "8", "9"]),
  ("Symbol, full set.", [[33,47],[58,64],[91,96],[123,126]], [], ["!", "\"", "#", "$", "%", "&", "\'", "(", ")", "*", "+", ",", "-", ".", "/", ":", ";", "<", "=", ">", "?", "@", "[", "\\", "]", "^", "_", "`", "{", "|", "}", "~"]),
  ("Symbol, excluded.", [[33,47],[58,64],[91,96],[123,126]], [29], ["!", "\"", "#", "$", "%", "&", "\'", "(", ")", "*", "+", ",", "-", ".", "/", ":", ";", "<", "=", ">", "?", "@", "[", "\\", "]", "^", "_", "`", "{", "}", "~"])]
for var i in testCase {
  var member: [String] = []
  print("\(i.condition) ", terminator:"")
  if i.result == GenerateMember().getMember(range: i.range, exclude: i.exclude) {
    print("\u{001B}[0;32m=> OK\u{001B}[0;30m")
  } else {
    print("\u{001B}[0;37m=> NG\u{001B}[0;30m")
  }
}

こんな感じ。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です