質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

748閲覧

高階関数をつかって、多次元配列から要素を見つける書き方を教えて下さい。

mskRR

総合スコア6

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2020/09/11 23:08

下のfor-in文で書いているような多次元配列から要素を見つける方法をlazy.filterのようにかけないでしょうか?

配列をflatにする方法なら思いつくのですが、その場合はlazy.filterのメリットが消えてしまうと思いまして。

swift

1 2let mdArray = [[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]] 3 4func find(_ int: Int) -> Int? { 5 6 var count = 0 7 8 for i in mdArray { 9 10 for j in i { 11 12 for k in j { 13 14 count += 1 15 print(count) 16 17 if k == int { 18 return k 19 } 20 21 } 22 } 23 } 24 return nil 25} 26 27let i = find(5) 28

swift

1let array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 2 3let r = array.lazy.filter { $0 == 5 } .first 4 5print(r) // (6 times)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

unhappychoice

2020/09/12 04:25

> lazy.filterのメリット は何を指しているでしょうか? (実行速度?メモリ効率? 質問例では - filter を1チェーンしかしていないので lazyの意味がない - lazy.filter{}.first だとリストの要素すべてを走査 + 1つだけ残った配列分メモリ確保される のでそもそも for での実装例よりパフォーマンスが悪いと思います。 また、1つ見つけるという操作は lazy にできないので、質問の意図がわかっていないですmm
mskRR

2020/09/12 09:53 編集

playgroundで確認したろころ array.lazy.filter { $0 == 5 }.first // => 6times array.filter { $0 == 5 } .first // => 11times となっていましたので、 timesがなにを表しているか調べませんでしたが、当然全要素にアクセスしていないと解釈してました。 この場合のlazyはリスト要素すべてを走査 + 1つだけ残った配列分メモリを確保するのですね。 知りませんでした、ありがとうございます。 メリットはforとの比較でのメリットではなく、 配列をフラットにした後に、lazy.filterするとコスト的なメリットがなくなると考えたのですが、 unhappychoiceが教えてくださったような動作をするようでしたら、もともとlazyをつけることにメリットはないということですね。
unhappychoice

2020/09/12 07:45

> この場合のlazyはリスト要素すべてを走査 + 1つだけ残った配列分メモリを確保するのですね。 あ、これは for文 で書いたときに比べ、filterの返り値に余分に新しい配列を作るので、の対比でした lazy は map / filter を複数チェーンしたときに、都度配列を作らなくするため、メモリと実行速度が向上するというものです。 (ので、複数チェーンしない限りは基本的に意味はない
mskRR

2020/09/12 08:08 編集

playgroundのtimesってなんですかね。arrayとfilterとfirstしか書いてないんですが。
MasakiHori

2020/09/13 04:41

LazyFilterSequenceは元のSequenceとfilterの関数だけを持ったstructで生成時点では新たな配列は生成していません firstなどのcomputedなプロパティやメソッドが呼ばれた時に初めて要素に対して関数等が適用されます この時戻り値としての値が生成された段階でSequenceの走査を打ち切りますのでその分効率が良いということです lazy.filter{ ... }.firstであれば たとえば1万の要素があったとしても1番目の要素がfilter関数にtrueを返せばfilter関数は1度しか実行されません。もちろんSequenceの走査も1要素のみです
mskRR

2020/09/13 11:52

MasakiHoriさんの説明で、今まで自分が学習したことがそれほど間違っていないことを確認できて安心しました。
guest

回答1

0

ベストアンサー

残念ながらlazyではfilter関数の実行を減らす事は出来ますが元のfor-inを使ったものと同等のものは書けません。
以下のコードほぼ同等のものとなります。

swift

1func find(_ n: Int) -> Int? { 2 3 mdArray.lazy.flatMap { a0 in 4 a0.lazy.flatMap { 5 $0.lazy.filter { $0 == n } 6 } 7 }.first 8}

複数テストを行ってみましたがパフォーマンス的にはfor-inとあまり変わらないと思われます。
(ぱっと思い付いたテストデータを使っただけなので断定は出来ません)
ただ、ここまでして高階関数で書くよりも、多次元の配列を使わない設計にしたほうがいいとは思います。

投稿2020/09/13 05:28

MasakiHori

総合スコア3384

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mskRR

2020/09/13 11:47

ありがとうございます。 なるほど、flatMapにlazyをつけれるわけですね。気づきませんでした。 今回の場合は可読性が高いコードになるわけでもないようなので、根本から考え直してみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問