{ }codelper

学ぶ › JavaScript

制御フロー · 08

真偽値と三項演算子

真偽を変数に入れておく、二つの値から一つを選ぶ、「このどれかか」をたずねる。

「条件分岐」の単元では、比較を if の中でそのまま使いました。
今回はその結果を値として扱います。
下の例は曜日と客の年齢を読み、週末かどうかと子どもがいるかどうかを変数に入れておき、週末なら 12、平日なら 8 の入場料の合計を表示します。

const lines = require("fs").readFileSync(0, "utf8").split("\n");const day = lines[0].trim();const ages = lines[1].trim().split(/\s+/).map(Number); const weekend = ["sat", "sun"].includes(day);   // 포함 검사의 결과(참·거짓)를 변수에 담아요let child = false;                              // 깃발: 아직 어린이를 못 봤어요for (const age of ages) {  if (age < 13) child = true;} const price = weekend ? 12 : 8;                 // 두 값 중 하나를 골라요console.log(weekend ? "weekend" : "weekday");console.log(price * ages.length);console.log(child ? "child" : "adults");
stdin
sat
35 41 9
stdout
weekend
36
child

ポイント

  • 比較の結果(age < 13)は真偽値です。
    数や文字列と同じように変数に入れておいて、何度も使えます。
    入れておいた値は条件の場所にそのまま書きます。
    if (weekend) で十分で、== true は付けません。
  • フラグは、真偽値の変数を繰り返しと一緒に使う形です。
    繰り返しの前で偽にしておき、探していたものに出会ったら真に変えます。
    繰り返しが終わると「一つでもあったか」が残ります。
  • 三項演算子は、条件によって二つの値のどちらかを選びます。
    if はすることを選び、三項は値を選びます。
    だから代入の右側や出力の中にそのまま書けます。
  • 三項は短いときだけ使います。
    三項の中にまた三項を入れるようになったら、if と else で書き直すほうが読みやすくなります。
  • 含まれるか判定は「この値はこれらのどれかか」をたずねます。
    == を || で長くつなぐ代わりに、値をリストに入れて「入っているか」を1回だけたずねます。
    答えは真偽値です。
  • 真偽値をそのまま出力すると、言語によって違います。
    Python と C# は True、JavaScript・Java・Craykon は true、C と C++ は 1 です。
    だから例では三項で文字列を選んで表示しています。

言語ごとの書き方

Pythonweekend = day in ("sat", "sun")、フラグは child = False から True へ。
三項は 12 if weekend else 8 — 真のときの値がいちばん前に来ます。
否定は not weekend
JavaScriptconst weekend = ["sat", "sun"].includes(day);、三項は weekend ? 12 : 8。
in は含まれるか判定ではありません。
"sat" in ["sat", "sun"] は false です(値ではなく番号があるかをたずねます)
TypeScriptJavaScript と同じです。
型の名前は boolean です
Javaboolean weekend = List.of("sat", "sun").contains(day);、三項は weekend ? 12 : 8。
文字列一つと比べるときは day.equals("sat")
C#bool weekend = rest.Contains(day); — 配列に使うには using System.Linq; が必要です。
三項は weekend ? 12 : 8
C++bool weekend = std::find(rest.begin(), rest.end(), day) != rest.end();(<algorithm>)、三項は weekend ? 12 : 8。
bool をそのまま出力すると 1 で、先に std::boolalpha を送ると true
C#include <stdbool.h> を入れると bool、true、false が使えます。
含まれるかを調べる道具がないので、繰り返しで一つずつ strcmp(day, rest[i]) == 0 かを見ます。
1文字なら strchr("aeiou", c) != NULL。
三項は weekend ? 12 : 8
Craykonweekend = ["sat", "sun"].含む(day);、フラグは child = 偽; から 真 へ。
三項は weekend ? 12 : 8。
文字列にも "aeiou".含む("e") のようにたずねられます

よくある間違い

== "sat" or "sun" で「どちらかか」をたずねたPython · JavaScript · TypeScript · C · C++ · Craykon

day = "mon"
if day == "sat" or "sun":
    print("weekend")
else:
    print("weekday")

→ weekend — 月曜日なのに週末になります。(day == "sat") or "sun" と読まれるので、前が偽なら "sun" が条件になり、空でない文字列は真です

両側とも比較で書きます(day == "sat" or day == "sun")。
含まれるか判定ならもっと短くなります(day in ("sat", "sun"))。
Java と C# はこのコードをコンパイルエラーで止めてくれます。

フラグを else で偽に戻した

int[] ages = {9, 35, 41};
boolean child = false;
for (int age : ages) {
    if (age < 13) child = true;
    else child = false;
}
System.out.println(child ? "child" : "adults");

→ adults — 9歳がいるのに、子どもはいないことになります。9 で真になったあと、35 と 41 でまた偽に上書きされました。こう書くと、フラグには「最後の客が子どもか」しか残りません。どの言語で書いても同じです

else を消します。
フラグは繰り返しの前で1回だけ偽にしておき、繰り返しの中では真に変えるだけにします。
繰り返しの中で child = age < 13; のように毎回入れ直すのも同じミスです。

三項をかっこなしで + のあとに付けたJavaScript · TypeScript · Python · C++ · Craykon

const ok = false;
console.log("Result: " + ok ? "yes" : "no");

→ yes — + が先に計算されます。"Result: false" という文字列が条件になり、空でない文字列なのでいつも真です。Craykon も yes を表示します。Python の "Result: " + "yes" if ok else "no" は no だけを表示し、C++ の std::cout << ok ? "yes" : "no"; は 0 を表示します

三項全体をかっこで囲みます:"Result: " + (ok ? "yes" : "no")。
Java と C# はかっこがないとコンパイルエラーで知らせてくれます。

言語ごとの違い
条件の場所に真偽値でない値を入れたとき、言語は二つに分かれます。
Java と C# はコンパイルエラーで止めます。
C・C++・Python・JavaScript・TypeScript・Craykon は "sun" のような値も真とみなして進みます。
何を偽とみなすかも言語によって違います。
空のリストは Python では偽ですが、JavaScript と Craykon では真です。
一つ目と三つ目のミスが黙って間違った答えを出すのはそのためです。
条件には比較か真偽値の変数だけを書く習慣をつけると安全です。

練習問題