「頭の鍛え方・使い方」はなぞなぞに学べ!記憶力も向上させる、考え方のコツ
なぞなぞは好きでしょうか?
算数なぞなぞ!2+3=10、7+2=63、それでは9+5=??? : ジャポンタ
より
なぞなぞを解くときの頭の使い方
ここでは上の画像のような、算数の問題のなぞなぞの話に限りますが
なぞなぞを解くとき、どうやって考えますか?
実は、ここでは「仮説・検証」の姿勢があるんです!
仮説と検証って大事なの?
仮説は、知っての通り「きっとこうだろう...」という予測を立てることですよね。
検証は、実際に確かめる事
つまり、なぞなぞを解くとき
「こういう法則なんじゃないか?」
という仮説から
「本当に当てはまっている」
となるまで検証をするわけです。
で、何がいいの?
仕事をする上ではもちろんですし
勉強する時もそうですが
「自分で、仕組みを考える」ことが非常に大事です。
仕事の時は、課題を解決するときに
何が原因になっているのかを突き止めるためには
仮説と検証が必要になりますし
勉強をするとき、新しい概念を学ぶときなどは
行間を読むような
「なんだこれ?こんな感じなのかな...?」
という解釈を繰り返す人ほど、吸収が速かったりします。
具体的には?
例えば、さっきの画像
算数なぞなぞ!2+3=10、7+2=63、それでは9+5=??? : ジャポンタ
より
まずは、上の4つの中から法則を見つけるところからです
ここでは、地頭の良さやIQなどが問題にされることが多いですが
とりあえず、見つかったことにしましょう。
2+3=10のところで
(2+3)×2=10
とすれば、普通の式になります。
この式を見て、どういう法則があるか分かりますよね?
和を左側の数字にかけるんです。
さて、次は検証です。
普通、2.3個当てはまれば十分だとは思うので
(8+4)×8 = 96
・・・
後は省略します。
となり、答えは
(9+5)×9=126
ではないか?ということになります。
結局なにが大事なの?
ここで、一番重要なのは
「こうなっているんじゃないか?」
という予測をもつことです。
勉強の面でも
「習っていないからできない」
とか
「初めて見た。」
と言って、すぐ人に聞く人がいるかと思います
もちろん、質問すること自体を悪くいうつもりはありません。
(質問する内容を選ぶことは非常に大事です。
良質な情報は、良質な質問から得られることが多いです。)
その前に、一旦自分で法則を予想してみたらどうでしょうか。
それは、間違っていても、当てはまっていても
あなたの記憶に残るはずです。
「言葉が上手く伝わらない...」と悩んでいる人に、知っておいてほしいたった1つのこと
「ちょっとその機械の電源付けといてくれない?」
と言われた時、あなたは下のどちらのボタンを押しますか?
左でしょうか、右でしょうか
きっと、パソコンなどの電子機器をよく使う人は右側のボタンを押すかと思います。
けれど、左も電源ボタンです。(昔のWindowsを閉じる時のアイコンです)
言葉が伝わらないとはどういうことか
ここで、前提として理解してほしいことがあります。
それは言葉が伝わらないとは「自分がイメージしているものと、言葉を聞いた相手が考えたイメージが異なる」ということです。
つまり、言葉を伝えることの最終目的はイメージを正しく伝える事にあります。(もちろん、伝えたくないときは別ですが...)
自分が思いつくイメージや、相手が思いつくイメージは今までの経験や知識、性格などに大きく影響されます。
今まで、「上手く言葉を伝えられない」と思い込んでいた人
全て「あなたの責任」というわけではありません。
ただし、そんな中でも「できる限り正確に」イメージを伝える方法があります。
知っておくべき1つのこと
相手に物を伝える時は
「できるだけ、相手の知識や経験に合わせて、又は経験や知識が無い場合にも通じるように」言葉を選ぶことが必要です。
例えば
「ちょっと」などという表現は避けたほうがいいでしょう。
(曖昧な表現をしたいときは別です)
今、近くにテレビがある人はテレビを、無い人はそれくらい大きなものに当てはめてほしいのですが
「そのテレビちょっと動かしてくれない?」
と言われたとき、あなたはどれくらい動かしますか?
2cm?3cm?それとも10cmくらい動かせば希望通りなんでしょうか。
だったら元々
「そのテレビ20センチくらい横に動かしてくれない?」
と頼まれた方がやりやすいはずです。
ただ、ここでも頼んだ側の20cmのイメージと頼まれた側の20cmのイメージが異なる可能性は残ります。
それくらいの誤差は容認されることが多いとは思います。
どうしても、そのズレを生んではいけないとき、例えば工場などといった操作が必要になる場所では
「そのラインまで動かしてくれる?」
といった、方法が使えます。その「ライン」という標を使うことで、「誰でも」・「同じように」できるように設定されています。
普段の生活でそこまで細かな頼みごとがあることは少ないと思うので
再度言いますが、しっかりと認識してほしい事は
「できるだけ、相手の知識や経験に合わせて、又は経験や知識が無い場合にも通じるように」言葉を選ぶことが必要だということです。
経験や知識に関わらない伝え方
じゃあ、どうすればいいの?
という人に対して、とりあえずここから始めよう!という言葉の選び方はあります。
最初は言葉を選ぶことで「時間を要する」こともあると思います。
「相手に話しかけるためだけに時間を使うなんて...」
と、軽く見ないでください。
相手に言葉が上手く伝わらなくて、修正にかかる時間の方が圧倒的に手間になります。
相手との信頼も失います。
相手の知識や経験に関わらない物の伝え方の練習は結構大事で
- 数値・固有名詞を入れる事(例:「2cm」,「丸が閉じているボタン」など)
- 色など、人間の認識に固有の特徴があるものを利用する。
1については例に書いた通りです。
2に関してですが、人は色に関して抱く感覚が似ています。
例えば、赤や黄色は「危険」そうなイメージを持ちますし、青はその反対であることが多いです。
一方、○は「良い」印象を持つのに対し、×は「良くない」印象を持ちます。
(ここでは、×が本当に悪いかどうかわからないじゃないかといった言及は控えて頂けると助かります)
下のリンクで細かく分類されているので参考にしてください。
こういう事を理解していると、話言葉だけでなく、資料作成などにも役に立ちます。
例えば、自分の担当部門外の人達へプレゼンテーションをするとき、生徒にプレゼンテーションをするとき、研修で新人に教える時
経験の差は圧倒的です。
そんな場所でも、せめて90%は正しく情報が伝わるように努力すること
それが大事になります。
あなたが何か物を買ったとき、「マニュアル」はほとんどの場合ついてきます。
あの「マニュアル」は、「経験のある」人が「経験の無い」ユーザーに向けて書かれています。
そういった観点から見てみると、あのうんざりな取扱説明書も意外と面白いものに思えてきませんか?
VBA InputBoxで入力を受け付ける。InputBoxを繰り返す。
マクロの記録でできることをやっていても面白くないので(記録したコードから勉強することはいいことなのですが)
今回はInputBoxを使います。
InputBoxの使い方
Sub Training() 'InputBoxの使い方 Dim st As String st = InputBox("入力してください") MsgBox st + "が入力されました" End Sub
これをボタン1に登録し、実行します
いい感じですね。複数回呼び出すやり方としてfor や whileがあります。
他のプログラミングでもこの繰り返しはおなじみなので説明は省略します。
'説明:セルのA1~A10に1~10を入力する Sub test() For i = 1 To 10 Worksheets("Sheet1").Cells(i, 1).Value = i Next End Sub
こんな感じです。今回は入力回数を任意の数で辞める方法を考えます。
While True を使い、Exit Subを用いる
While True Wend
とすることで無限に繰り返しが起こります。
ここで、あるタイミングで条件分岐をしExit Subをすることで操作が終わります。
その例として、
Sub InputTraining() While True Dim result As Integer result = MsgBox("入力を行いますか",vbYesNo) If result = 7 Then MsgBox("終了します") Exit Sub[f:id:rkprog:20151027152555p:plain] End if Dim st As String st = InputBox("入力してください") MsgBox st+"が入力されました" Wend End Sub
こうすることで、任意のタイミングでループを抜けることが出来ます。
MsgBox,InputBoxの返り値に関しては以下のサイトを見てください。
MsgBoxにvbYesNoのオプションを付けると、Noが押されたときresultが7になります。Yesが押されると6になるのですが今回はどうでもいいです。
実際に実行してみると上手くいくのが分かるかと思います。
最後に読み込んだ値を書き込む
まず、入力された値をセルA1に入れます。
Sub InputTraining() While True Dim result As Integer result = MsgBox("入力を行いますか", vbYesNo) If result = 7 Then MsgBox ("終了します") Exit Sub End If Dim st As String st = InputBox("入力してください") Cells(1, 1) = st ' Range("A1") = st Wend End Sub
これで、毎回A1にデータが残ります。今回、Cellsを使ったのですがRangeの方がなじみのある人はそちらを使ってください。
ただこれではA1に上書きされていくので、下に連ねていくためにCellsの行を指定します。
Dim L As Integer L = Cells(Rows.Count, 1).End(xlUp).Row + 1
を使うことで今まで書かれている最終行の次の行を取得できます。
これを入れて
Sub InputTraining() While True Dim result As Integer result = MsgBox("入力を行いますか",vbYesNo) If result = 7 Then MsgBox("終了します") Exit Sub End if Dim L As Integer L = Cells(Rows.count,1).End(xlup).Row+1 Dim st As String st = InputBox("入力してください") Cells(L,1) = st Wend
これでうまくいっているのが分かるかと思います。
これを応用して列番号を切り替えていくことで名前と点数を連続で入力していけます。
ExcelでVBAを使うまで。-Excelでマクロを使えるようにする-
VBAを使うまで
簡単な環境設定みたいなものです。
まず、Excelを開いてください。
「ファイル」から「オプション」を選んで
「リボンのユーザー設定」から「開発]にチェックを
これで、Excelに開発タブが増え、表示にマクロができます。
このマクロで、記録する機能を使うだけでも十分違いますので、今回その説明も加えて。
例えばシート内の全ての文字を消したい場合
これで、マクロの記録をします。全消しの場合は全て選んでDeleteを押せばいいだけなので、それをMacro1として保存します。
終わったら記録終了を押しましょう。
これで、Macro1は全て消す操作になります。
この実行方法ですが
この「開発」タブの挿入からボタンのようなものを選ぶことで、図の中のボタンのようなものが作れます。この時、マクロを選ぶ画面がでますので、そこで選べばいいだけです。
実行するときはクリックするだけ。
C++ クラスの復習。オブジェクト指向っぽく
クラスの復習
今回はUserクラスという物を作成し、名前と点数を持たせます。
#include<iostream> #include<string> #define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0])) using namespace std; class User{ private: string name; int score; int rank; public: User() { name = "none"; score = 0; } User(string st) { name = st; score = 0; } User(string st,int a) { name = st; score = a; } void setscore(int a) { score = a; } int getscore() { return score; } string getname() { return name; } };
クラスの最後に;を忘れないように
ここでは、Userクラスの宣言とともに初期化を行う、コンストラクタを定義しています。
コンストラクタはvoidなどの返り値の型を宣言する必要が無いので気を付けてください。(宣言したらビルドエラーでした)
この部分
User() { name = "none"; score = 0; } User(string st) { name = st; score = 0; } User(string st,int a) { name = st; score = a; }
これで初期化して、名前と点数を呼び出してみようと思います。
#include<iostream> #include<string> #define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0])) using namespace std; class User{ private: string name; int score; int rank; public: User() { name = "none"; score = 0; } User(string st) { name = st; score = 0; } User(string st,int a) { name = st; score = a; } void setscore(int a) { score = a; } int getscore() { return score; } string getname() { return name; } }; int main() { User a("taro",60); cout<<"name:"<<a.getname()<<" score:"<<a.getscore()<<endl; return 0; }
実行結果
こんな感じです。名前のみの場合
と点数が0になっているのが分かるかと思います。
(欠席した場合、0点的な・・・)
複数人にした場合
int main() { User taro("taro",60); User hanako("hanako",90); User takeshi("takeshi",30); User jiro("jiro",100); cout<<"name:"<<taro.getname()<<" score:"<<taro.getscore()<<endl; cout<<"name:"<<hanako.getname()<<" score:"<<hanako.getscore()<<endl; cout<<"name:"<<takeshi.getname()<<" score:"<<takeshi.getscore()<<endl; cout<<"name:"<<jiro.getname()<<" score:"<<jiro.getscore()<<endl; return 0; }
と変更すれば、人数は増えますが・・・
ということで配列に変更することに。
その場合、set出来る関数があったほうが楽なので作成
void set(string st, int a) { name = st; score = a; }
int main() { User user[4]; user[0].set("taro",60); user[1].set("hanako",90); user[2].set("takeshi",40); user[3].set("jiro",100); for (int i = 0; i < ARRAY_LENGTH(user); i++) { cout<<"name:"<<user[i].getname()<<" score:"<<user[i].getscore()<<endl; } return 0; }
これで
いい感じですね。
今日はここまでで
#include<iostream> #include<string> #define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0])) using namespace std; class User{ private: string name; int score; int rank; public: User() { name = "none"; score = 0; } User(string st) { name = st; score = 0; } User(string st,int a) { name = st; score = a; } void setscore(int a) { score = a; } void set(string st, int a) { name = st; score = a; } int getscore() { return score; } string getname() { return name; } }; int main() { User user[4]; user[0].set("taro",60); user[1].set("hanako",90); user[2].set("takeshi",40); user[3].set("jiro",100); for (int i = 0; i < ARRAY_LENGTH(user); i++) { cout<<"name:"<<user[i].getname()<<" score:"<<user[i].getscore()<<endl; } return 0; }
C++ クラスと関数の扱い。public と private
今、練習中に気づきましたが
C++でarrayで安易にsizeofを使おうとすると大変なことになりますね。
int a[5]; for(int i = 0; i < sizeof(a);i++){ cout<<a[i]<<endl; }
とかやろうとすると、上手くいかないんですね。
こういうときは
sizeof(array) / sizeof(array[0])
を使うようですね。
実際
#include<iostream> #include<string> using namespace std; int main() { int a[5] = { 0,0,0,0,0 }; cout << sizeof(a) << endl; return 0; }
とすると
20らしいです。
sizeof(array) / sizeof(array[0])
を使うと
となっていい感じです。
これはもう定義しておきましょう。
#include<iostream> #include<string> #define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0])) using namespace std; int main() { int a[5] = { 0,0,0,0,0 }; cout << ARRAY_LENGTH(a) << endl; return 0; }
クラスと関数
クラスの作り方ですが、すごく適当に言えばこんな感じ。
#include<iostream> #include<string> #define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0])) #define NUM 5 using namespace std; class Stack{ public: int value = rand() % 100 + 1; }; int main() { Stack a; Stack b; return 0; }
{}を閉じるタイミングがすごく慣れないです。
これでStackクラスが出来ました。したのint main()の所でStackクラスの変数を2つ宣言しています。
このaとbはvalueの値を持っているので、ピリオドで繋ぐことで使うことが出来ます。出力してみると
#include<iostream> #include<string> #define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0])) #define NUM 5 using namespace std; class Stack{ public: int value = rand() % 100 + 1; }; int main() { Stack a; Stack b; cout << "a=" << a.value << endl; cout << "b=" << b.value << endl; return 0; }
いい感じですね。
ここでpublicとprivateの差に入ります
publicとprivate
とりあえず、public→privateへ変換
#include<iostream> #include<string> #define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0])) #define NUM 5 using namespace std; class Stack{ private: int value = rand() % 100 + 1; }; int main() { Stack a; Stack b; cout << "a=" << a.value << endl; cout << "b=" << b.value << endl; return 0; }
これで実行しようとするとビルドエラー
こんなエラーが出ています
エラー C2248 'Stack::value': private メンバー (クラス 'Stack' で宣言されている) にアクセスできません。
要は、privateにするとStackクラス内からしか操作できなくなります。もちろん出力だけも禁止です。今回エラーの原因は15,16行目ですね。
なので、出力する関数をStackクラス内に書きます。
class Stack{ private: int value = rand() % 100 + 1; public: int getvalue(); }; int Stack::getvalue() { return value; }
といって取得する関数でもいいですし
class Stack{ private: int value = rand() % 100 + 1; public: void getvalue(); }; void Stack::getvalue() { cout<<value<<endl; }
でもいいです。
ここで、クラス内でちゃんと返り値などの定義もしてあげないと動かないので(これが分かるのに時間かかった・・・)注意してください。
set等も同様に行うことで、関数を経由しないと数値が操作できなくなります。勝手に値を変えられないように制限するために使ったりするのかな?
#include<iostream> #include<string> #define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0])) #define NUM 5 using namespace std; class Stack{ private: int value; public: int getvalue(); void setvalue(); }; int Stack::getvalue() { return value; } void Stack::setvalue() { cin >> value; } int main() { Stack a; Stack b; a.setvalue(); b.setvalue(); cout << "a=" << a.getvalue() << endl; cout << "b=" << b.getvalue() << endl; return 0; }
C++ 複数入力。defineの使い方からバブルソートとセレクションソートなどの並び替え
バブルソート
複数入力をするとどうなるのか
要はこれです。どうなるのか
int main() { string a; int b; cin >> a >> b; cout << a << endl; cout << b << endl; return 0; }
実行結果
普通にEnterを押して複数個入力できるようです。
意外と楽ですね。
ソート人数の設定
一つの方法として#defineを使って最初に人数を定義しておく。
こんな感じ
#include<iostream> #include<string> #define NUM 5 using namespace std; int main() { return 0; }
こうすることでNUMが5という値になります。データの数を先に決めておく的な。
実行結果出すまでもないので・・・
最初にNUMをすることで、この後のプログラムを書く際にNUMの定義を変えれば人数を変えれることになります。柔軟になるということですね。
とりあえずこのままバブルソートへ
まずはNUM回の入力から。名前も入れましょうか。
#include<iostream> #include<string> #define NUM 5 using namespace std; int main() { string name[NUM]; int score[NUM]; for (int i = 0; i < NUM; i++) { cout << i + 1 << "人目の名前を入力してください" << endl; cin >> name[i]; cout << i + 1 << "人目の点数を入力してください" << endl; cin >>score[i]; } for (int i = 0; i < NUM; i++) { cout << i + 1 << ":" << name[i] << " " << score[i] << endl; } return 0; }
実行結果
上手くいっていますね。
今回のソートは昇順で流していくことにしましょう。昇順ができれば降順に変える方法は簡単なので。
同時に最大・最小も出力しましょう。
以上纏めると今回やることは
- バブルソートを行い、昇順にする
- 最高点の名前・点数を出力
- 最低点の名前・点数を出力
ではまず、バブルソートから
#include<iostream> #include<string> #define NUM 5 using namespace std; int main() { string name[NUM]; int score[NUM]; for (int i = 0; i < NUM; i++) { cout << i + 1 << "人目の名前と点数を入力してください" << endl; cin >> name[i]; cin >>score[i]; } for (int i = 0; i < NUM; i++) { for (int j = NUM - 1; j > i; j--) { if (score[j-1]>score[j]) { int a = score[j - 1]; score[j - 1] = score[j]; score[j] = a; string b = name[j - 1]; name[j - 1] = name[j]; name[j] = b; } } } for (int i = 0; i < NUM; i++) { cout << i + 1 << ":" << name[i] << " " << score[i] << endl; } return 0; }
実行結果
上手くいっていますね。
次は最大最小です。
といっても簡単で、これは最大・最小が更新されるたびにその[i]の値を残しておけばいいでしょう。
int型でmaxindexとminindexを宣言します。初期値を0にすることで、データが1個の時の最大値・最小値は1人目の点数になります。
#include<iostream> #include<string> #define NUM 5 using namespace std; int main() { string name[NUM]; int score[NUM]; int maxindex = 0; int minindex = 0; for (int i = 0; i < NUM; i++) { cout << i + 1 << "人目の名前と点数を入力してください" << endl; cin >> name[i]; cin >>score[i]; if (score[i] > score[maxindex]) { maxindex = i; } if (score[i] < score[minindex]) { minindex = i; } } cout << "最高点は" << name[maxindex] << " " << score[maxindex]<<endl; cout << "最低点は" << name[minindex] << " " << score[minindex]<<endl; for (int i = 0; i < NUM; i++) { for (int j = NUM - 1; j > i; j--) { if (score[j-1]>score[j]) { int a = score[j - 1]; score[j - 1] = score[j]; score[j] = a; string b = name[j - 1]; name[j - 1] = name[j]; name[j] = b; } } } for (int i = 0; i < NUM; i++) { cout << i + 1 << ":" << name[i] << " " << score[i] << endl; } return 0; }
実行結果
上手くいっていますね
乱数を使ってデータを入力する。
なんだか、AさんとかBさんとか毎回入力するのもバカバカしくなってきたので、ここも自動でやってもらいます。
C++にforeachのような構文があるのかよくわからないので、ここは配列を普通に使用してrandを使えば勝手に名前と点数を入れてくれるかな。
#include<iostream> #include<string> #define NUM 5 using namespace std; int main() { string name[NUM] = { "A","B","C","D","E" }; int score[NUM]; int maxindex = 0; int minindex = 0; for (int i = 0; i < NUM; i++) { cout << name[i] << "さんの点数:"; score[i] = (rand() % 100) + 1; cout << score[i] << endl; if (score[i] > score[maxindex]) { maxindex = i; } if (score[i] < score[minindex]) { minindex = i; } } cout << "最高点は" << name[maxindex] << " " << score[maxindex]<<endl; cout << "最低点は" << name[minindex] << " " << score[minindex]<<endl; for (int i = 0; i < NUM; i++) { for (int j = NUM - 1; j > i; j--) { if (score[j-1]>score[j]) { int a = score[j - 1]; score[j - 1] = score[j]; score[j] = a; string b = name[j - 1]; name[j - 1] = name[j]; name[j] = b; } } } for (int i = 0; i < NUM; i++) { cout << i + 1 << ":" << name[i] << " " << score[i] << endl; } return 0; }
実行結果
随分と楽になりました。
ここから先は名前とかどうでもいい(大学などで課題で出る場合は必要なのでしょうが)ので、点数のみでソートをかけることにしましょう。コードも少し長くなって見づらくなってきたので。
NUM 10に変更し
nameを消しました。
#include<iostream> #include<string> #define NUM 10 using namespace std; int main() { int score[NUM]; for (int i = 0; i < NUM; i++) { score[i] = (rand() % 100) + 1; cout<< i+1 <<":"<< score[i] << endl; } cout << endl; for (int i = 0; i < NUM; i++) { for (int j = NUM - 1; j > i; j--) { if (score[j-1]>score[j]) { int a = score[j - 1]; score[j - 1] = score[j]; score[j] = a; } } } for (int i = 0; i < NUM; i++) { cout << i + 1 << ":" <<score[i] << endl; } return 0; }
実行結果
いい感じですね。
それではセレクションソートへ。
セレクションソート
これは、最小(又は最大)の選び出し、昇順ならば一番上に吹っ飛ばし、次は一番上以外の数字の中で最小の数を探し、二番目にぶっ飛ばすソートです。
先ほどと同様、minindexを導入しましょう。
内部ループ(jのループ)では直接のデータ交換は無しです。あくまで最小の値を持つindexを保存するだけです。
外部ループ(iのループ)でデータを交換してください。
#include<iostream> #include<string> #define NUM 10 using namespace std; int main() { int score[NUM]; int minindex; for (int i = 0; i < NUM; i++) { score[i] = (rand() % 100) + 1; cout<< i+1 <<":"<< score[i] << endl; } cout << endl; for (int i = 0; i < NUM; i++) { minindex = i; //初期化 for (int j = i; j < NUM; j++) { if (score[minindex] > score[j]) { minindex = j; } } int a = score[i]; score[i] = score[minindex]; score[minindex] = a; } for (int i = 0; i < NUM; i++) { cout << i + 1 << ":" <<score[i] << endl; } return 0; }
実行結果
と、セレクションソートでした。
次はNUMの値を任意に変えても繰り返せるようになりたいですね。