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

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

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

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

1回答

456閲覧

C#のジャグ配列で、配列の要素を維持したまま合計値でソートすることは可能ですか?

rinmeda317

総合スコア12

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

0クリップ

投稿2017/11/29 16:09

###前提・実現したいこと
C#でジャグ配列を作り、一次元目の要素の合計値で二次元目の要素をソートしたいのですが、ソートした後に一次元目の要素を使いたいです。
今コンソールに表示されている例で言えば、Gene[0][]の合計が7、Gene[1][]の合計が5、Gene[2][]の合計が7、Gene[3][]の合計が6なので、配列の二次元目を{0,2,3,1}というようにソートし、上位二つであるGene[0][]の要素とGene[2][]の要素を後で使用したいです。
なので一次元目の要素を維持したまま一次元目の要素の合計値で二次元目の要素をソートする方法を探しています。そのようなことは可能でしょうか?

###コンソールの表示

Gene[0] 0111010111 Gene[1] 0110010011 Gene[2] 0111101011 Gene[3] 1011101001

###該当のソースコード

C#

1 2class Run 3{ 4  public static void Main() 5 { 6 Random rnd = new Random(); 7 int[][] Gene; 8 9 for (int i = 0; i < 4; i++) 10 { 11 Gene = new int[4][]; 12 Gene[i] = new int[10]; 13 for (int j = 0; j < 10; j++) 14 { 15 Gene[i][j] = rnd.Next(0, 2); 16 } 17 Console.WriteLine("Gene[{0}]", i); 18 foreach (int ge in Gene[i]) 19 { 20 Console.Write(ge); 21 } 22 Console.WriteLine(); 23 } 24 } 25}

###試したこと
Array.Sortを試してみましたが、ジャグ配列でそのまま使うとエラーになるんですね…

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

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

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

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

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

guest

回答1

0

ベストアンサー

配列の二次元目を{0,2,3,1}というようにソートし

説明を読むと少し混乱しましたが、次のような並び替えをするというふうに解釈しました。

text

1before => after 2Gene[0] 3A:0111010111 A:... 4Gene[1] 5B:0110010011 C:... 6Gene[2] 7C:0111101011 B:... 8Gene[3] 9D:1011101001 D:...

もしそうでないなら本回答はスルーしてください。もし上の通りなら「配列の一次元目をソート」と表現するのが普通な気がします。

さて、上記を前提と考えるならこれは普通のソートと言えると思います。LinqでもArray.Sortでも実現できますが、とりあえず「ソートできればよい」という前提での例を挙げますと・・・

C#

1// Linq 2int[][] sorted = Gene.OrderByDescending(row => row.Sum()).ToArray(); 3 4// Array.Sort 5 6int[] keys = Gene.Select(row => -row.Sum()); // (1) 7Array.Sort(keys, Gene); 8 9// なお(1)は概ね以下のような処理を表しています。 10int[] keys = new int[Gene.Length]; // int[]を生成すると初期値は0であることが保証されている 11for (int i = 0; i < keys.Length; i++) { 12 foreach (int e in Gene[i]) keys[i] -= e; 13}

LinqのOrderByはキーの計算を各々の要素に対して1度しかしないのでキーの計算量が大きくても非効率とはならず、一次元目の構造を再構築する関係でメモリー消費量が多めにかかるという感じだと思います。また安定ソートなのですね。今回初めて知りました。

上のArray.Sortはkey配列を使う例です。他にComparison<int[]>, IComparer<int[]>を使うパターンもありますが、それらは比較する回数だけキー計算が必要になりキー計算量が大きい場合は不利ですので上の例の方が早い気がします。なおArray.Sortは安定ソートではないそうです。単純なクイックソートを採用しているのかも知れません。

速度とメモリー消費量、安定ソートかどうかなどについては研究してみるとよいと思います。自分の場合は巨大な配列をソートすることなどないのでもっぱらLinqでよいと考える方です。要素数のオーダーが数千・数万になる場合は一応調べてから選ぶかも知れません・・・

投稿2017/11/29 18:06

編集2017/11/29 18:44
KSwordOfHaste

総合スコア18394

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

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

rinmeda317

2017/11/29 18:29

深夜にもかかわらず丁寧な回答ありがとうございます。 その解釈で合っています。 当方C#は初心者なのでLinqはよくわからず、Array.Sortを使ってみようと思ったのですが、例をそのまま入れてみたらエラーになりました… エラーメッセージは「'int[][]' does not contain a definition for 'Select' and no extension method 'Select' accepting a first argument of type 'int[][]' could be found (are you missing a using directive or an assembly reference?) (CS1061)」と「 Use of unassigned local variable 'Gene' (CS0165)」でした。
KSwordOfHaste

2017/11/29 18:39 編集

多分 using System.Linq; としていないからではないでしょうか。 ーーーちょっと補足します。Array.Sortの例でkeysを求めるのにLinqを使っているのです。Linqを使わずに単純にforループで作ってもよいと思います。そういう例にした方がわかりやすかったかも知れませんね。
rinmeda317

2017/11/30 00:16

初歩的な質問で申し訳ないのですが、 foreach (int e in Gene[i]) keys[i] -= e; この行の処理がどうなっているのか教えていただけないでしょうか。 また、for文の外にこのスクリプトを書く場合、変数Geneの呼び出しが必要みたいなのですが呼び出し方がよくわかりません。
KSwordOfHaste

2017/11/30 00:35

i行目の全てのデータをkeys[i]から減算するという意味です。 for文など基本的な文法は別途しっかり確認してくださいね! >変数Geneの呼び出しが・・・ 自分はソートする部分のみコードを挙げたのです。全体はご自分で考えてみてほしいです。
rinmeda317

2017/11/30 05:05

失礼しました。 何日も考えていてもうまくいかず自信喪失していたみたいです。 本をまた読み返して考えてみるとします。 付き合ってくださってありがとうございました。
KSwordOfHaste

2017/11/30 07:40

コード自体は少しデバッグをすれば動きそうな雰囲気に見えます。ここでひと踏ん張りするのが上達のコツだと思います。1点だけ指摘しておきましょう。 Gene = new int[4][]; はそれを囲むfor文の外側でやらないといけません。Geneを宣言している行で下記のように同時に初期値を代入するのがよいと思います。 int[][] Gene = new int[4][];
rinmeda317

2017/12/01 06:40

言われてみればGene = new int[4][];をfor文の中で宣言しなければいけない理由はありませんね…ありがとうございます。
rinmeda317

2017/12/01 10:21

おかげさまで、遺伝的アルゴリズムのOneMax問題のスクリプトを完成させることができました。本当にありがとうございます!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問