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

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

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

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

Q&A

解決済

1回答

2482閲覧

swiftの関数で引数によって次元の違う配列を返す方法はありますか?

hi_ro_kun

総合スコア7

Swift

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

0グッド

0クリップ

投稿2016/03/01 14:31

編集2016/03/01 15:06

配列の宣言をする際に、条件によって次元の違う配列を戻り値としたいケースがあります。
しかし、関数の実装時に戻り値の配列の次元を決められてしまっているため、以下のような
テストケースの場合、コンパイルエラーとなり、思うように動作してくれません。
このようなケースで上手く動くようなプログラムは書けるのでしょうか?
戻り値の型推論ができると聞き、クロージャの説明を読んでみましたが、今ひとつピンと
きません。もし何かしらの方法があるのであればご教授していただけないでしょうか。

Swift

1func test(gotit: Bool) -> [Int] { return gotit ? [[1,2,3],[4,5,6]] : [1,2,3,4,5,6] }

追記(ご指摘に対する対応)
詳細を説明せず、大変失礼いたしました。 実は、C++の得意な友人より、多次元配列の宣言が面倒な言語は 使う気になれないとバカにされ、何とか関数実装できないかと考え、 以下のような関数を作成したのですが、同じ関数で違う次元の 配列を返すことができればと思い相談させていただきました。

Swift

1func Array1<T>(index: [Int], rV: T) -> [T] { return [T](count: index[index.count-1], repeatedValue: rV) } 2func Array2<T>(index: [Int], rV: T) -> [[T]] { return [[T]](count: index[index.count-2], repeatedValue: Array1(index, rV: rV)) } 3func Array3<T>(index: [Int], rV: T) -> [[[T]]] { return [[[T]]](count: index[index.count-3], repeatedValue: Array2(index, rV: rV)) } 4 5var sw: [[[Bool]]] = Array3([2,3,2], rV: true) 6print(sw) 7// [[[true, true], [true, true], [true, true]], [[true, true], [true, true], [true, true]]] 8 9var dbl: [[[Double]]] = Array3([2,2,3], rV: Double(0.0)) 10print(dbl) 11// [[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]], [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]]

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

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

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

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

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

Stripe

2016/03/01 14:43

その関数の呼び出し元では、その戻り値をどのように扱うんですか?
hi_ro_kun

2016/03/01 15:02

詳細を説明せず、大変失礼いたしました。 実は、C++の得意な友人より、多次元配列の宣言が面倒な言語は 使う気になれないとバカにされ、何とか関数実装できないかと考え、 以下のような関数を作成したのですが、同じ関数で違う次元の 配列を返すことができればと思い相談させていただきました。 func Array1<T>(index: [Int], rV: T) -> [T] { return [T](count: index[index.count-1], repeatedValue: rV) } func Array2<T>(index: [Int], rV: T) -> [[T]] { return [[T]](count: index[index.count-2], repeatedValue: Array1(index, rV: rV)) } func Array3<T>(index: [Int], rV: T) -> [[[T]]] { return [[[T]]](count: index[index.count-3], repeatedValue: Array2(index, rV: rV)) } var sw: [[[Bool]]] = Array3([2,3,2], rV: true) print(sw) // [[[true, true], [true, true], [true, true]], [[true, true], [true, true], [true, true]]] var dbl: [[[Double]]] = Array3([2,2,3], rV: Double(0.0)) print(dbl) // [[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]], [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]]
Stripe

2016/03/01 15:16

ん?? test()関数はどこへ行ったのですか? そのArray1()、Array2()、Array3()は、今回の質問とどのような関係があるんですか?
hi_ro_kun

2016/03/01 15:29

わかりにくくてすみません。test()関数そのものにそれほど意味はなく、一つの関数で、条件により、一次元配列、二次元配列など、異なる次元の配列を戻り値として返せるのかどうかを質問するためにシンプルに必要部分を抜き出したものとご理解ください。 また、Array1()、Array2()、Array3()に関しては、多次元配列の宣言の際に記述をシンプルにするための関数となっています。Array2()は二次元配列の、Array3()は三次元配列の宣言及び初期化を行います。引数 index: [Int] は各次元の要素数を、rVは初期値となっています。 現状の仕様では、二次元配列を使用する場合はArray2()を、三次元配列を使用する場合はArray3()を呼び出すため、もっとスマートにならないかと考えています。言葉足らずであればすみません。
guest

回答1

0

ベストアンサー

関数の戻り値の型をAnyにすれば、動的にどんな値でも返せます。
ただし、呼び出し元でキャストしないと、その値にアクセスできません。

投稿2016/03/01 15:26

Stripe

総合スコア2183

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

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

hi_ro_kun

2016/03/01 15:36

一度、以下のようにAnyを試してみたのですが、再帰部分のコンパイルエラーで上手く行きません。 根本的な考え方を変えた方が良いのでしょうか。 func ArrayAll<T>(index: [Int], d: Int, rV: T) -> Any { return d==1 ? [T](count: index[index.count-d], repeatedValue: rV) : [T](count: index[index.count-d], repeatedValue: ArrayAll(index, d:d-1, rV: rV)) }
hi_ro_kun

2016/03/01 15:39

追記、なお引数dはDimension(次元)のことです。
Stripe

2016/03/01 15:42

ジェネリックを使わずに、Anyにしてください。
hi_ro_kun

2016/03/01 16:01

素早い返信、ありがとうございます。 ジェネリックを使わずに、Anyにとのことですが具体的にどこをAnyにすべきでしょうか? 何ぶんジェネリックも試行錯誤で使ってみたような状態で今ひとつ腑に落ちておりません。 ご教授いただけると嬉しいです。
Stripe

2016/03/01 16:05

rVの型をTからAnyにしてください。
hi_ro_kun

2016/03/01 16:12

すみません、以下のように書き換えましたがうまく行きません。 また [T] の部分を [Any] に変えてみましたがやはり同様です。 func ArrayAll<Any>(index: [Int], d: Int, rV: Any) -> Any { return d==1 ? [T](count: index[index.count-d], repeatedValue: rV) : [T](count: index[index.count-d], repeatedValue: ArrayAll(index, d:d-1, rV: rV)) }
Stripe

2016/03/01 16:15

ジェネリックは使いません。 func ArrayAll(index: [Int], d: Int, rV: Any) -> Any { return d==1 ? [Any](count: index[index.count-d], repeatedValue: rV) : [Any](count: index[index.count-d], repeatedValue: ArrayAll(index, d:d-1, rV: rV)) }
hi_ro_kun

2016/03/01 16:23

コンパイルエラーが出ず、コンパイルできました。 ありがとうございます。 なお、下記のコードより呼び出したところ、型キャストがうまくいってない?ためか、 こちらでコンパイルエラーとなりました。配列の型キャストの方法が間違っているのでしょうか。 var tbl: [[[[[Int]]]]] = [[[[[Int]]]]](ArrayAll([2,2,2,2,2], d: 5, rV: 1)) print(tbl)
Stripe

2016/03/01 16:32

キャストには、as?を使ってください。 if let a = ArrayAll([2,2], d: 2, rV: 11) as? [Any] { print(a) if let b = a[0] as? [Any] { print(b) if let c = b[0] as? Int { print(c) } } }
hi_ro_kun

2016/03/01 16:44

うまくいきました!! ありがとうございました。 as? や Any など使用したことのない機能を使う機会に恵まれ、 また一つ成長できたように思います。 貴重なお時間を割いてきただき、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問