0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

SwiftのArrayを特定の要素で区切ってグループ化したいときにchunkedが使えた

Posted at

実行環境

Xcode14.1

前置き

swift-algorithmsを利用してうまくリファクタリングできたので紹介したい。
この中のchunkedを使用した。

どのような機能かはこちらがわかりやすかった。
https://qiita.com/jollyjoester/items/4e5df18e4f5c0429ee9e#chunked

Chunkは「かたまり」のことです。
コレクションを複数のサブシーケンスに分割します。

やりたいこと

SwiftのArrayを特定の要素で区切りたいことがあった。
具体的なケースとして、NaturalLanguage Frameworkの利用時に発生した例を示す。
NaturalLanguage Frameworkで文字列を解析したときに、文字列を記号や単語などにタグ付してくれる。この中の単語の部分を記号で区切りたかった。

具体例のコードを示す。
文字列を解析するコード

import NaturalLanguage

typealias TextTag = (text: String, tag: NLTag)
func makeTagByNL(text: String) -> [TextTag] {
    let tagger = NLTagger(tagSchemes: [.lexicalClass])
    tagger.string = text
    let options: NLTagger.Options = [.joinNames, .omitWhitespace]
    
    var array = [(String, NLTag)]()
    tagger.enumerateTags(in: text.startIndex..<text.endIndex, unit: .word, scheme: .lexicalClass, options: options) { tag, tokenRange in
        if let tag = tag {
            array.append((String(text[tokenRange]), tag))
        }
        return true
    }
    return array
}

利用例

let text = "野菜(じゃがいも(国産)、にんじん、とうもろこし)、トマトペースト"
let service = LinguisticService()
let result = service.makeTagByNL(text: text)

下記のようなデータが得られた。

text: 野菜, tag: OtherWord
text: (, tag: Punctuation
text: じゃがいも, tag: OtherWord
text: (, tag: Punctuation
text: 国産, tag: OtherWord
text: )、, tag: Punctuation
text: に, tag: OtherWord
text: ん, tag: OtherWord
text: じん, tag: OtherWord
text: 、, tag: Punctuation
text: とうもろこし, tag: OtherWord
text: )、, tag: Punctuation
text: トマト, tag: OtherWord
text: ペースト, tag: OtherWord

ここから記号を除去したいのだが、問題として野菜、じゃがいもなどはいいが、にんじんは文字列がバラバラになってしまっていた。バラバラな文字列は結合したい。そこで、結合のために単語を記号ごとにグループ化しようとした。

// 欲しいデータ
["野菜", "じゃがいも", "国産", "にんじん", "とうもろこし", "トマトペースト"]

実装

chunkedを使わない、リファクタリング前のコード。

事前にグループ化用のArray(oneWordArray)を用意して、記号が来たら保存用のArray(oneWordResult)に追加していった。 oneWordArray.reduce("") { $0 + $1 } で結合を行った。

func ommitPunctuation(array: [TextTag]) -> [String] {
    var oneWordArray = [String]()
    var oneWordResult = [String]()
    for wordAndTag in array {
        if wordAndTag.1 == NLTag.punctuation {
           if oneWordArray.count > 0 {
               let reduced = oneWordArray.reduce("") { $0 + $1 }
               oneWordResult.append(reduced)
               oneWordArray.removeAll()
           }
           continue
        }

        oneWordArray.append(wordAndTag.0)
    }
    if !oneWordArray.isEmpty {
        let reduced = oneWordArray.reduce("") { $0 + $1 }
        oneWordResult.append(reduced)
    }

    return oneWordResult
}

chunkedを使うリファクタリング後のコード

chunkedでtagが異なる場合に別のグループとするように指定した。
fileterで単語のみにした。
mapでグループごとに結合を行った。

func ommitPunctuation(array: [TextTag]) -> [String] {
    return array.chunked(by: {
        $0.tag == $1.tag
    }).filter {
        $0.first?.tag == .otherWord
    }.map {
        $0.reduce("") { $0 + $1.text }
    }
}

chunkedを使うことで見通しの良いコードを書くことができた。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?