LoginSignup
5
0

【UEFN】Verseのデザインパターンを考える - メソッドチェーン(配列編) -

Last updated at Posted at 2023-12-06

前回の続きです。
今回はメソッドチェーンを使った配列処理についてです。

前回はint型に対してメソッドチェーンを用いて実装するアプローチを紹介しました。
今回は配列を使ってメソッドチェーンを用いたより実践的なアプローチを紹介します。

配列の数だけ処理をループさせる

配列の数だけ処理をループさせる処理を書くシーンはUEFNでも数多くあります。
forはネストを深くしがちで関数の行数を増やすこともありますが以下のような実装をすることでコードを簡略化することができるかもしれません

// forでの例
Sample(): void =
  Array := array { 1, 2, 3, 4, 5 }
  for(Item : Array):
    Print("{Item}")
(Input:[]t where t:subtype(comparable)).ForEach(predicate: type{_(:t, :int, :[]t): void}): void = 
  for(X := 0..Input.Length):
    if(Item := Input[X]):
      predicate(Item, X, Input)


PrintAll(Value: int, Index: int, Input: []int): void = 
  Print("{Value}")

Sample(): void = 
  array { 1, 2, 3, 4, 5 }.ForEach(PrintAll) // 1 2 3 4 5が出力される

コード量的にはforで書いたほうがシンプルには見えますが、複雑な処理になってくると同じ配列に対して別タイミングで同じ処理のイテレーションを実行したいなどのニーズがあった場合コードの可読性を落とします。

※補足

Verseは無名関数をサポートしておらず、変数に関数を入れたり関数に直接関数を渡すような実装ができないため関数を切り出す形でForEachに関数を渡しています

配列の中から条件に一致する値を抽出する

次に以下のような関数を考えてみます。
int型の数字が適当に入った配列から偶数の値だけ抽出する関数

(Input:[]t where t:subtype(comparable)).Filter(predicate: type{_(:t): logic}): []t = 
  var Result: []t = array {}
  for(X := 0..Input.Length):
    if(Item := Input[X]):
      IsMatch :logic = predicate(Item)
      if(IsMatch = true):
        set Result += array { Item }
  Result

PrintAll(Value: int, Index: int, Input: []int): void = 
  Print("{Value}")
  
IsEven(Value: int): logic = 
  if(Mod[Value, 2] = 0):
    return true
  return false

Sample(): void =
  array { 1, 2, 3, 4, 5 }.Filter(IsEven).ForEach(PrintAll) // 2 4が出力される

Filter関数の中では条件に一致する配列を新しく生成し、返却する処理が書かれています。
配列の型は同じなのでForEachも後続でチェインすることができ、偶数で抽出した配列が出力されます。

この処理はユーザごとのデータが入った配列から特定のデータのユーザをピックするなどの処理に使用できます

配列の中の値を加工する

int型の配列の値すべてを2倍にする処理を書いてみましょう

(Input:[]t where t:subtype(comparable)).Map(predicate: type{_(:t): t}): []t = 
  var Result: []t = array {}
  for(X := 0..Input.Length):
    if(Item := Input[X]):
      set Result += array { predicate(Item) }
  Result

PrintAll(Value: int, Index: int, Input: []int): void = 
  Print("{Value}")

Double(Value: int): int =
  return Value * 2

Sample3(): void =
  array { 1, 2, 3, 4, 5 }.Map(Double).ForEach(PrintAll) // 2 4 6 8 10 が出力される

まとめ

上記のような処理を書くことで配列を検索したり加工したりなどの処理をメソッドチェーンで実現することが可能です。
このような実装を行うことでfor文の多用によるコードの難読化を防ぐことができるのでぜひ試してみてください

5
0
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
5
0