【Swift】split(separator: ) vs components(separatedBy:)

2つあるけど、どっちを使うか。

どっちから使っていくか。


"1 2 3".split(separator: " ")
// ["1", "2", "3"]

"1 2 3".components(separatedBy: " ")
// ["1", "2", "3"]

split のほうが短いし、分かりやすくね?

 

■ 最初と最後の区切り文字


" 1 2 3 ".split(separator: " ")
// ["1", "2", "3"]

" 1 2 3 ".components(separatedBy: " ")
// ["", "1", "2", "3", ""]

 

■ 連続する区切り文字


"1  2  3".split(separator: " ")
// ["1", "2", "3"]

"1  2  3".components(separatedBy: " ")
// ["1", "", "2", "", "3"]

 

■ 割れない場合


"123".split(separator: " ")
// ["123"]

"123".components(separatedBy: " ")
// ["123"]

"1 2 3".split(separator: "23")
// ["1 2 3"]

"1 2 3".components(separatedBy: "23")
// ["1 2 3"]

"1 2 3".split(separator: "  ")
// ["1 2 3"]

"1 2 3".components(separatedBy: "  ")
// ["1 2 3"]

 

■ 空文字で割る


"123".split(separator: "")
// ["1", "2", "3"]

"123".components(separatedBy: "") 
// ["123"]

"1 2 3".split(separator: "")
// ["1", " ", "2", " ", "3"]

"1 2 3".components(separatedBy: "") 
// ["1 2 3"]

" 1 2 3 ".split(separator: "")
// [" ", "1", " ", "2", " ", "3", " "]

" 1 2 3 ".components(separatedBy: "") 
// [" 1 2 3 "]

"  1  2  3  ".split(separator: "")
// [" ", " ", "1", " ", " ", "2", " ", " ", "3", " ", " "]

"  1  2  3  ".components(separatedBy: "")
// ["  1  2  3  "]

 

■ 空文字を分割


"".split(separator: " ")
// []

"".components(separatedBy: " ")
// [""]

"".split(separator: "23") 
// []

"".components(separatedBy: "23")
// [""]

"".split(separator: "  ")
// []

"".components(separatedBy: "  ")
// [""]

"".split(separator: "")
// []

"".components(separatedBy: "")
// [""]

 

■ それでも直感的に分かりづらいような


"123".split(separator: "123")
// []

"123".components(separatedBy: "123")
// ["", ""]

"123".split(separator: "23")
// ["1"]

"123".components(separatedBy: "23")
// ["1", ""]

"  1  2  3  ".split(separator: " ")
// ["1", "2", "3"]

"  1  2  3  ".components(separatedBy: " ")
// ["", "", "1", "", "2", "", "3", "", ""]

 

■ まとめ

それぞれ他にも引数はいろいろあるようですが、


components(separatedBy:)

のほうがはっきり明快で分かりやすいように思えますが。


"  1  2  3  "
  .split(separator: " ")   // ["1", "2", "3"]
  .joined(separator: " ")  // "1 2 3"

"  1  2  3  "
  .components(separatedBy: " ") // ["", "", "1", "", "2", "", "3", "", ""]
  .joined(separator: " ")       // "  1  2  3  "

将来的にどうなるのか。

👉 【Swift】なんとなくメソッド名が長い気がする hatena-bookmark
👉 swift - component(separatedBy:) versus .split(separator: ) - Stack Overflow hatena-bookmark


【SwiftUI】ストップウォッチ つくってみる ⏱

非同期処理 や Observable クラスの確認です。



Timer クラスというのがあるようなので

それもやって比較してみました。



 

⏱ @Obserevable ってシンプル

マクロ @Observable ひとつだけで書けるようになったんですね !

👉 【SwiftUI】今どきの データモデル (Model data) のマクロ記述 📝 hatena-bookmark
👉 Migrating from the Observable Object protocol to the Observable macro | Apple Developer Documentation hatena-bookmark

 

⏱ 謎な部分

macOS で ビルトインの Timer クラスが30秒につき7秒ぐらいも遅れる。

なんでなんやろ ?

👉 Timer | Apple Developer Documentation hatena-bookmark


【Swift】プロトコル と 型 の難しさを Array のextension 化で感じた初心者

以前、so でみつけたこういうコード。


extension Array where Element: Collection { 
  func toD1() -> [Element.Element] {
    return self.flatMap { $0 } 
  }
}

👉 【 Swift 】2次元配列と1次元配列の相互変換 🤔 hatena-bookmark

なんとなく「Collection」 の部分が気持ち悪かったのであれこれやってみます。

 

■ お題

2次元配列を平坦化します。


let data = [
  ["あ", "い", "う"],
  ["え", "お"]
]

print(data.flatMap { $0 })
// ["あ", "い", "う", "え", "お"]

print(Array(data.joined()))
// ["あ", "い", "う", "え", "お"]

これを extension 化しようとして、


extension Array {
  var flattened: [String] {
    flatMap { $0 }
  }
}


Instance method 'flatMap' requires that 'Element' conform to 'Sequence'

とエラーがでるとこからスタートです。

 

■ やってみた

ドキュメントや先人の記事を読んでおきます。

👉 Element | Apple Developer Documentation hatena-bookmark
👉 Array | Apple Developer Documentation hatena-bookmark
👉 [Swift]Array型 #Swift - Qiita hatena-bookmark

型や制約の記述を確認しながら進みます。


extension Array where Element == Array<String> {
  var flattened: [String] {
    // Array(joined()) // Cannot convert return expression of type 'Array<Array<String>>' to return type '[String]'
    // joined().map { $0 } // OK
    // Array<String>(joined()) // OK
    // [Element.Element](joined()) // OK
    // [String](joined()) // OK
    flatMap { $0 } // OK
}


extension [[String]] where Element == [String] {
  var flattened: [String] {
    flatMap { $0 }
  }
}

// ["あ", "い", "う", "え", "お"]


extension Array where Element == [String], Element.Element == String {
  var flattened: [Element.Element] {
    flatMap { $0 }
  }
}

// ["あ", "い", "う", "え", "お"]

ここで、制約を先祖のプロトコルのみにします。


extension Array where Element: Collection {
  var flattened: [Element.Element] {
    flatMap { $0 }
  }
}

// ["あ", "い", "う", "え", "お"]

揃えたほうが良さげです。


extension Collection where Element: Collection {
  var flattened: [Element.Element] {
    flatMap { $0 }
  }
}

// ["あ", "い", "う", "え", "お"]

スッキリしました !

Sequence でもいけるんですね。


extension Sequence where Element: Sequence  {
  var flattened: [Element.Element] {
    flatMap { $0 }
  }
}

// ["あ", "い", "う", "え", "お"]

👉 誰もが知りたいSequenceとCollectionのすべて hatena-bookmark

ちなみに、元の配列に nil を混ぜると、


let data = [
  ["あ", nil, "う"],
  ["え", "お"]
]

上手に処理してくれてますね!


// [Optional("あ"), nil, Optional("う"), Optional("え"), Optional("お")]

 

■ まとめ

プロトコルと型。

よく分かってませんが

なんだか深そうです。

そういえば、どこかに書いてました、

プロトコルを使用することによって得られる柔軟性と、特定の型のメソッドの作成の容易さのバランス

というようなフレーズ。

ありがとうございます。

どこか継承グラフみれるとことかあるのでしょうか ? 独自に書き出さずに。

👉 Dash for macOS - API Documentation Browser, Snippet Manager - Kapeli hatena-bookmark
👉 realm/jazzy: Soulful docs for Swift & Objective-C hatena-bookmark