###転置行列
基本ループからいきなり転置行列かよって自分でも思ってますが、
問題をチラ見したら頭から離れず、なかなかに手こずった問題です。
転置行列というのは、簡単にいうと、
横を行、縦を列とした行列があったときに、縦を横にしちまおう!というものです。
1 2 3
4 5 6
とあったら
1 4
2 5
3 6
とするみたいな感じですね。これを転置するっていうらしいです。
###とりあえず解いてみる
最初に思いついたのは、任意の数列を入力してもらってそれを元に処理していく形
import java.util.*;
public class Main {
int movecount = 0;
public void shift() {
Scanner scan = new Scanner(System.in);
System.out.printf("半角スペースで任意の数列を入力してください: ");
int[] first = shiftToArray(scan.nextLine());
System.out.printf("半角スペースで任意の数列を入力してください: ");
int[] second = shiftToArray(scan.nextLine());
System.out.printf("半角スペースで任意の数列を入力してください: ");
int[] third = shiftToArray(scan.nextLine());
System.out.println("転置後");
print(shiftToNewArray(first,second,third));
}
public int[] shiftToArray(String inputMojiretsu) {
String mojiletsu [] = inputMojiretsu.split(" ",0);
int numbers [] = new int[mojiletsu.length];
for (int i = 0; i < mojiletsu.length; i++){
numbers[i]= Integer.parseInt(mojiletsu[i]);
}
return numbers;
}
public int[][] shiftToNewArray(int[] array1, int[] array2, int[] array3) {
int[][] returnArray = new int[array1.length][3];
for (int i = 0; i < array1.length; i++) {
returnArray[i][0] = array1[i];
returnArray[i][1] = array2[i];
returnArray[i][2] = array3[i];
}
return returnArray;
}
public void print(int [][] outputArray){
for (int array [] : outputArray){
for(int i : array){
System.out.print(i + " ");
}
System.out.print("\n");
}
}
public static void main(String[] args) { new Main().shift(); }
}
俺のMac % java algo.java
半角スペースで任意の数列を入力してください: 1 2 3
半角スペースで任意の数列を入力してください: 4 5 6
半角スペースで任意の数列を入力してください: 7 8 9
転置後
1 4 7
2 5 8
3 6 9
いけた!と思いましたが、もう長すぎるし、二重配列のindexを決め打ちで書いているので、
数列が増えたり、要素が増えたりしたら太刀打ちできません。
それはもうアルゴリズムとは言えないのでは、、と思い立ち 改善を図ります。
最初にやったいたことは、入力された3つの行を、shiftToArrayメソッド
でint型の配列に変換し、
変換後の3つの配列をshiftToNewArrayメソッド
で1つの二重配列に変換しています。
二重配列への変換は下記のように行っており、1次元目の0,1,2要素目にそれぞれの3つの配列の共通インデックスの値を格納している感じです、
returnArray[i][0] = array1[i];
returnArray[i][1] = array2[i];
returnArray[i][2] = array3[i];
ループを回す回数をarray1と絞ってしまっているので、汎用性0ではありますが、
この各行の共通インデックスの値を持った配列を持った二重配列を作れば、転置が完成することが分かりました。。!
[ [array1[0]、array2[0]、array3[0]],[array1[1]、array2[1]、array3[1]],[array1[1]、array2[1]、array3[1]] ]
###改善してみる
import java.util.*;
public class Main {
public void shift() {
Scanner sc = new Scanner(System.in);
//行数を取得
int line = sc.nextInt();
//列数を取得
int row = sc.nextInt();
Scanner sc2 = new Scanner(System.in);
//列数分の要素(中身の要素数は行数)を持った2次元配列を生成
int outputArray[][] = new int[row][line];
//それぞれ行の共通インデックス部分を一つの配列に格納していく
for(int i = 0; i < line ; i++){
for(int j = 0; j < row; j ++){
outputArray[j][i] = sc.nextInt();
}
}
print(outputArray);
}
public void print(int [][] outputArray){
System.out.println("転置後");
for (int array [] : outputArray){
for(int i : array){
System.out.print(i+" ");
}
System.out.print("\n");
}
}
public static void main(String[] args) { new Main().shift(); }
}
俺のMac % java algo.java
1 2 3
4 5 6
転置後
1 4
2 5
3 6
便宜上、最初の入力で行数と列数を取得できるようにして、そこからは数列を順に処理していきます。
二重配列を二重ループで処理していますが、やっていることはシンプルで、2次元目の配列で、特定のインデックスに、順番に値を入れていっています。
2次元目の配列の要素数は列分だけ必要になるので、要素の中身を格納する内側のループ回数も列分だけ行うという感じです。
1回目のループ [ [1][2][3] ]→ それぞれの配列の1番目に各値を入れていく
2回目のループ [ [1,4][2,5][3,6] ]→ それぞれの配列の2番目に各値を入れていく
特定の配列に要素を詰めるという2重ループは使ったことがあるんですが、
各要素の特定のインデックスに値を入れていくというのが慣れておらず動いた瞬間はよく分かりませんでした笑
インデックスだけみるともう少し分かりやすいかもしれません。
1ループ目 | 2ループ目 |
---|---|
outputArray[0][0] | outputArray[0][1] |
outputArray[1][0] | outputArray[1][1] |
outputArray[2][0] | outputArray[2][1] |
こうすることで、列をそのまま行に持っていくことができました!
###学んだこと
- 行列とかは特に配列で考えていった方が良いし、まずはシンプルな数で考えてみる
- 数字を紙に起こして書いてみて、どうやったら期待値が生まれるか、インデックスの番号付きで書いていくと整理できる
頭で悩んでもしょうがないので、単純な数で期待通りにするにはどう操作したら良いのかを頭の中でイメージして。。
そこから、処理に落とし込むという順番が良いかもしれませんね。。!
2重ループは苦手意識が強いんですが、使いこなせれば冗長なコードも避けられるしスッキリするので、引き続き頑張っていきます!