Learning to Code

プログラミング勉強記録

SQLの書き方 GROUP BYとORDER BYの違いなど

バックエンドの言語としてPHPを勉強することにした。
RubyよりPHPのほうが求人が多かった、というだけの理由だ。
PHPというとやはりLAMPとして使用するケースが多いのか、ウェブ上で教材を探すと
ApacheMySQLの知識をある程度前提として書かれているものが多い気がする。
データベースの勉強は今まで全くしてきていないので、基礎知識だけでもやっておこうと思っている。

参考にしているのはこちら ⇛ SQL SELECT Statement

・クエリ 基本の構文

全部はカバーできないが見直し用も兼ねて一部だけまとめる。

SELECT * FROM table_1;

SELECTでデータベースから特定のデータを取り出す。
アスタリスクは全てのデータを取り出す時に使う。FROMでテーブルを指定する。
文末にはセミコロンをつける。
大文字・小文字はどちらも機能するが大文字が一般的?

SELECT * FROM Customers WHERE Name='Taro' OR Name='Ken';

WHEREで特定の条件に一致するデータのみ抽出するようフィルターをかけられる。
ORやANDでつなげることによって複数条件の設定が可能。

SELECT * FROM Guests WHERE NOT Country='Spain' AND NOT Country='France';

このようにWHERE NOT、AND NOTとNOTによる探し方も可能。
この場合は国がSpainでもなく、 かつFranceでもない(両方を満たす)データだけが抽出される。

SELECT * FROM Customers ORDER BY Country DESC;

ORDER BYで結果を昇順/ 降順に並べて抽出できる。昇順はASC (ascending)、降順はDESC (descending)。

INSERT INTO Guests (FirstName, LastName, Address, Sex, ZipCode, Country) 
VALUES ('Taro', 'Sato', 'Chuo-ku, Tokyo', 'Male', '123-4567', 'Japan');

INSERT INTOでテーブルに値を挿入できる。
INTOの後に挿入箇所、VALUESの後に挿入する値を入れる。順番が一致するよう注意。
※IDはデータ追加すると勝手に連番で追加されるので手動で追加は必要ない。

UPDATE Characters
SET CharacterName = 'Isono', City= 'Tokyo'
WHERE CharacterID = 1;

UPDATEはデータの上書きをする。WHEREで指示しないと全データが上書きされるので要注意!
DELETEもほぼ同じ使い方だがDELETE FROMとなる。

SELECT SUM(column_name) FROM table_name WHERE condition;

SUM、AVG、MIN、MAXなどExcelっぽい機能も利用可能。
SELECT SUM(column_name) AS XXXと記述するとAS以降で指定した列名でデータを抽出できる。

SELECT * FROM Customers WHERE CustomerName LIKE '_r%';

LIKEを使うと条件検索する場合に部分一致でも検索できる。
"%" と "" (アンダースコア)をワイルドカードとして使う。
%は0もしくは任意の(字数は問わない)文字、
は任意の1文字を表す。
上の例だと、CustomerNameの2文字目が"r"のデータを抽出する。

SELECT COUNT(CustomerID), Country
FROM Customers
GROUP BY Country;

GROUP BYはSUMやAVGなど集計機能と一緒に使われることが多い。
上の例ではGROUP BYがないとCustomerIDの合計件数だけが抽出されるが、
GROUP BYによって国別のデータが取れる。

...残りは後日。。

【JavaScript】VoidとUndefinedの話、==と===の話など

初めてのコードレビューをして頂く機会があったので、以下に(分かる範囲で)覚え書き。 独学者にとっては貴重な経験であった。やっぱり一人でやっているとこういうのが分からないので、 いつの間にか変な癖がつくということになりかねないですね。

・undefinedかどうか確かめたい時は、undefinedは使わない

以下のコードは、入力された値(number)が0もしくは空欄(入力なし)だった場合にアラートを表示させるためのもの。

function makeColRow() {
    let number = prompt("Enter a number between 1 to 100 to make grids.");
    if(number == false || number == undefined || number == null) { // *
        let message = alert("The number is invalid. Enter a number between 1 to 100.");
    } 

// *numberがundefinedかどうか確かめたい場合は、number === void(0)を使う

undefinedだと万が一ローカルあるいはグローバルで変数の値が上書きされていた場合、 予想しない挙動になる可能性がある。
実際にはあまりなさそうだが、undefined = "example";などとすることも可能ではあるため。単純に変数が定義されているかどうかを確かめるのであれば、 常にundefinedを返すvoid演算子を使うのが良い。

nullとundefinedを区別しなくてよければ、number == nullとしてもチェックは出来る。
(そういう意味では上記のコードはそもそもnumber == undefinedは必要なかった)
ただnull === undefinedではないので、100%の厳密なチェックではない。

厳密なチェックをするなら、typeof number === "undefined"でも可能。

・判定にはダブルイコールではなくトリプルイコールを

これはどこか他の記事でも読んだような気がする。
ダブルイコールだと厳密な判定が出来ないので、思わぬバグにつながる可能性が出てくる。
コードがとりあえず期待通りに動くと何となく見過ごしてしまいがちだが、トリプルしか使わない癖をつけるほうが良さそう。 当然、これだとダブルイコールで動いていたものが動かないということもある(上記がまさにそのケース)ので、 書き方も工夫が必要。のちほど書き直したコードを載せる。

・ifのネストは最大2つまで

ifの中にelse ifが2つも3つも入っているのは読みづらいし、テスト時も見直しづらいので極力分かりやすくすること。 できればifは1つで済ませるのが理想。可読性は非常に重要ということが分かった。

これがダメな例。横長すぎて読みづらい。

function makeColRow() {
    let number = prompt("Enter a number between 1 to 100 to make grids.");
    if(number == false || number == undefined || number == null) {
        let message = alert("The number is invalid. Enter a number between 1 to 100.");
    } else if(number > 100) {
            let message = alert("The number is invalid. Enter a number between 1 to 100.");
        } else if(number <= 100) { // ifが全部で3つもある
                resetGrids();
                let square = number * number;
                let gridcounter = 0;
                while(gridcounter < square) {
                    let columns = document.createElement('div');
                    columns.className = 'columns';
                    container.appendChild(columns);
                    gridcounter++;
                }
                let clmcounter = 0;
                while(clmcounter < number) {
                    let gridtemplateclm = `grid-template-columns: repeat(` + number + `, 1fr)`;
                  let gridtemplaterow = `grid-template-rows: repeat(` + number + `, 1fr)`;
                    container.setAttribute("style", gridtemplateclm + `;` + gridtemplaterow);
                    clmcounter++;
                }
            }
    addHoverEffect();
    rounds++;
}
・結果的にこうリファクタリングした
function makeColRow() {
    let number = prompt("Enter a number between 1 to 100 to make grids.");
    number = Number(number);
    if(number === 0 || isNaN(number) === true || number > 100) {
        let message = alert("The number is invalid. Enter a number between 1 to 100.");
    } else if(number <= 100) {
            resetGrids();
            let square = number * number;
            let gridcounter = 0;
            while(gridcounter < square) {
                let columns = document.createElement('div');
                columns.className = 'columns';
                container.appendChild(columns);
                gridcounter++;
            }
            let clmcounter = 0;
            while(clmcounter < number) {
                let gridtemplateclm = `grid-template-columns: repeat(` + number + `, 1fr)`;
              let gridtemplaterow = `grid-template-rows: repeat(` + number + `, 1fr)`;
                container.setAttribute("style", gridtemplateclm + `;` + gridtemplaterow);
                clmcounter++;
            }
        }
    addHoverEffect();
    rounds++;
}

しかしこうして見ると、whileが2つ入っているのも本当は別で関数を作って呼び出すべきなのかもしれない。

・さらにリファクタリング
function makeDivs(number) {
    let square = number * number;
    let gridcounter = 0;
    while(gridcounter < square) {
        let columns = document.createElement('div');
        columns.className = 'columns';
        container.appendChild(columns);
        gridcounter++;
    }    
}

function makeGrids(number) {
    let clmcounter = 0;
    while(clmcounter < number) {
        let gridtemplateclm = `grid-template-columns: repeat(` + number + `, 1fr)`;
      let gridtemplaterow = `grid-template-rows: repeat(` + number + `, 1fr)`;
        container.setAttribute("style", gridtemplateclm + `;` + gridtemplaterow);
        clmcounter++;
    }
}

function makeColRow() {
    let number = prompt("Enter a number between 1 to 100 to make grids.");
    number = Number(number);
    if(number === 0 || isNaN(number) === true || number > 100) {
        let message = alert("The number is invalid. Enter a number between 1 to 100.");
    } else if(number <= 100) {
            resetGrids();
            makeDivs(number);
            makeGrids(number);
        }
    addHoverEffect();
    rounds++;
}

1個1個の関数がだいぶ見やすい!
最初と比べるとかなり差があるのではないか。
バグがあっても問題を追うのがだいぶ楽そうではある。

とにかく動かせるように読みやすさはあまり考えずに書いていたが、これからはより綺麗にコードを書くよう心がける。

paizaスキルチェック Bランクになりました

先日、「Bランクむずい」という記事を書いたが、


f:id:yzume:20180208182544p:plain

通過しました。

ちなみに解いたのはこの問題。

B022:選挙の演説 paiza.jp
いくつかやった中では比較的簡単なほうの問題なのかなという印象。
これも十分時間かかったし、頭抱えたけど・・・
「全く解き方が分からない・・・」と絶望するレベルではなかった。

ちなみに、もっとランク上げてやろうと思ってAランクの問題も受けたけど、 普通に分からなかった。頭悪いのかなーとか、向いてないのかな〜とかちょっと悩んだけど、 まあそのうち出来るようになるよね、と気持ちを切り替えた。

そもそも、「アルゴリズムが苦手」と言っても、解き方が想像できないこともあれば、 自分の思う解き方をプログラミング言語で実装する書き方が分からない場合もあると思う。 どっちも勉強すればある程度のレベルまでは出来るようになるはず。 もちろん、センスのある人はひと目で解き方が分かったりするんだろうけど、それはまた別の話。

「勉強すれば分かる」ということは、逆にいえば勉強しないと分からないわけで、放っておいても出来るようにはならない。 言語の勉強は引き続きしていくが、考え方の部分も少し学ぼうと思い、この本をAmazonで注文した。
 
www.ohmsha.co.jp

ガチガチの教科書っぽい本のがいいのかもしれないが、とりあえずはこういうのを眺めながら、 問題を柔軟に考えられる癖をつけられたらいいなーと思っている。

paizaスキルチェック Bランクの壁

paiza転職で用意されているスキルチェックを少しずつ解いている。

最近はJSの勉強がメインだったため、Rubyの書き方が以前より怪しくなっているが、
現時点で一番まともに書ける言語のためRubyで挑戦している。

今のCランクから次のBランクまでがなかなか難しい。

この問題は事前の動作確認が不十分で不合格になった。 直後に再チャレンジして解いた。

f:id:yzume:20180204194428p:plain
paizaスキルチェック1

そしてこの問題は1回で解けたものの、解答に時間がかかりすぎてCランクになってしまった。

f:id:yzume:20180204194432p:plain
paizaスキルチェック2

決して「実際は出来てた」アピールではない・・・

別に実務では何回だって動作チェックできるし・・・
時間かかったって解けないのと解けるのじゃ意味が全然違うし・・・
結局正解してるし・・・(⇐負け惜しみ)




・・・クヤシイです!!

【JavaScript】TDDをするためにNode.jsとJasmineを導入する(Ubuntu 16.04)

・Test Driven Development(テスト駆動開発

実際にコードを書く前に、動作を自動で確認するテストコードを書いて、
そのテストが合格するように開発を進める方法。

テストがないと一回一回手動で機能の確認をしないといけないので、ミスを見逃しがちだし、
時間もかかる。テストを書いてから機能開発というと二度手間っぽいというか、
効率は悪そうだが実際はこっちのほうがスピーディと言われている。

JavaScriptをテストするには

テストをするには言語ごとに異なる環境を整える必要がある。 RubyRspecは聞いたことがあったが、JavaScriptでテストをするにはNode.jsを使えるようにする必要がある。

JavaScriptはブラウザ上で動く言語だが、 Node.jsはサーバー上でも動くJavaScriptとのこと。
普及した理由は、クライアントサイドもサーバーサイドも同じ言語(JavaScript)で書けて楽だから、
ということらしい。

参考: 

eng-entrance.com

Node.jsをインストールすると、Jasmineというテスト用のフレームワークが使えるようになる。
まずはこれらの環境を整えることから始める。

実際はこのあたりのことも散々調べてからようやく分かった。
最初はJasimineをapt-getしたらすぐ使えるようになるだろくらいにしか考えていなかった。
一応GithubのREADMEは見たものの、内容がさっぱり分からない(今でもいまいち分からない)。

github.com

・Node.jsとnpmをインストール

Node.jsを使うに当たってnpmという言葉にも遭遇。 これはNodeのパッケージ管理ツールで、ここにNode.jsで使える便利なツールが次々と開発されては追加されているらしい。
つまりここにJasimineも出てくるわけだが、まずはNodeのインストールから。

色々ググったがまずはこのサイトを参考にNodeをインストール。

jp.godaddy.com

いつも通りapt-getを使ってインストール。
Node.jsをインストールすると自動的にnpmもインストールされるらしいというのはこの時は知らず、
両方インストールした。

sudo apt-get update
sudo apt-get install nodejs
sudo apt-get install npm

※ここで注意書きが。Ubuntuでは他のプログラムとの干渉を避けるため
 Node.jsはnodeではなくnodejsというコマンドが割り当てられているとのこと。
 これを見落としたために後に混乱する原因に・・・

このサイトを見ると、「インストールされたか確認するにはnodejs -vを実行するように」
とあるのだが、なぜかnode -vを実行しては"No such file or directory"のエラーで慌てるということを繰り返してしまった。

www.digitalocean.com

実はインストールされたか確認する前に、適当なディレクトリ上にインストールをしてしまったため、
ルートディレクトリに移動させようとGUI上で色々動かしていた。 node -vがエラーになるのはそれが原因だと勝手に思い込み、ドツボにはまったのであった。
注意書きをちゃんと見ていればそんな目には合わなかったのに・・・
npmのサイトにはUbuntuのことに言及がなく、node -vで確認してねと書いてあることも余計に混乱する要因になった。

www.npmjs.com

その後もpackage.jsonのファイルを書き換えてみたり、設定を色々いじってみたのだが、
何かしらのエラーが出続け、場当たり的に対処したものの...
最終的にはこのエラーが解決しない状態となった。"/usr/bin/env: node: No such file or directory"

結果的にはnodejsにnodeへの仮想リンクを貼る("ln -s /usr/bin/nodejs /usr/bin/node")という方法でこのエラーは解消することが出来た。 node -vnodejs -vも正しく動作する。

・Jasmineをインストール

JasmineのGithubに、npmを利用したインストール方法が書かれているのでこれを参考に実行。 グローバルインストールとローカルインストールの違いがいまいち分からず、 かつこれに関してはどこででも使えたほうが良いのかなと思ったため、 グローバルを実行(その後うまく動かなかったのでローカルインストールも実行した。コンフリクトがあれば削除する気だったが今のところ正常)。

# Local installation:
npm install --save-dev jasmine

# Global installation
npm install -g jasmine

Jasmineでテストをするには、まずテスト対象のjsファイルと、テスト自身を書き込むspec.jsファイルが必要。 jsファイルには以下のように書き込む。var以下の関数部分は普段通り。 最後の行のmodule.exports=の部分にはファイル名を入力し、テスト用のspec.jsファイルが読み込めるようにする。

// ファイル名: helloWorld.js  

var helloWorld = function() {
  return 'Hello, World!'
}

module.exports = helloWorld

テスト用のファイルはこんな感じ。あくまで実行環境を整えるところまでしかやっていないので、 記法はまだ分からない。ぱっと見でだいぶイメージは湧きやすいが。 helloWorldの関数を実行した時に、"Hello, World!"という文字列が実行されればパスするというテスト。

var helloWorld = require('./helloWorld');

describe('Hello World', function() {
  it('says hello world', function() {
    expect(helloWorld()).toEqual('Hello, World!');
  });
});

ファイル構成は以下の通り。jsファイルとspec.jsファイルは同じディレクトリ内に置く必要がありそう。

hello_world/
 ├ node_modules/
 ├ spec/
  │   └ helloWorld.js
  │   └ helloWorld_test.spec.js
  ├ package.json
  │ 
・テストを実行するには コマンド

以下のどれでも実行できる。

1 npm test

2jasmine-node helloWorld_test.spec.js

3jasmine helloWorld_test.spec.js

ただし3番目のコマンドだとメッセージ内容が簡略化されたものになる。
1か2のほうが使いやすそうな印象。

【JavaScript】2〜nまでの素数を全て表示するには?

タイトル通り、2から任意の数(n)までの間にある素数を全て表示する関数を作ったので公開。
といっても1つの関数で実現したわけではないですが・・・  

let n = 0;

function testPrime(n) {     // nが素数ならコンソールに表示
  if (n === 1) {
    return false;
  } else if (n === 2) {
    console.log(n);
  } else {
    for (let x = 2; x < n; x++) {
      if (n % x === 0) {
        return false;
      }
    }
  console.log(n);
  }
}

function doTestPrime() {

let i = 0;
let uptoNumbers = [];  // 空の配列を作る

n = prompt("数を入力して下さい。");

while (n > 1) {      // n, n-1, n-2...というふうに全ての数を配列に加える
  uptoNumbers.push(n);
  n--; 
}

let arrayLength = uptoNumbers.length;

while (i < arrayLength) {
  testPrime(uptoNumbers[i]); // 配列の要素全てに対して素数かどうか確認する
  i++;
}
}

doTestPrime();

多分もっと簡単にやる方法があるはずだけど、とりあえず数時間悩んで作ったので、
しまっておくのももったいない!と思い公開。