配列の内容を処理していく時だが、交互に処理内容を変えたいときがある。
例えば要素をリストタグで囲って表示するのに背景色を交互に変えたいといった時だ。
PHPではこの作業は多分頻繁に発生するだろう。

$names = array("Tatsunori", "Koji", "Greisinger", "Hisanori", "Nomaguchi");

上のような配列があったとして

<li class="foo">Tatsunori</li>
<li class="bar">Koji</li>
<li class="foo">Greisinger</li>
<li class="bar">Hisanori</li>
<li class="foo">Nomaguchi</li>

こんな出力を得たいといった時だ。
これを実現するのはそれほど難しくない。

$names_size = count($names);
for ($i = 0; $i < $names_size; $i++) { if ($i % 2 == 0) $class = ' class="foo"'; else $class = ' class="bar"'; echo "<li$class>$names[$i]</li>\n"; }

こんなコードを書けばいい。
これはループの中で使っているカウンタ用の変数$iが2で割り切れるかをチェックしてその値により処理を分けている。
もしくはこんなコードでもいいだろう。

for ($i = 0, $b = true; $i < $names_size; $i++, $b = !$b) {
    if ($b) $class = ' class="foo"';
    else $class = ' class="bar"';
    echo "<li$class>$names[$i]</li>\n";
}

ここではカウンタ用の変数$iを初期化するタイミングで変数$bをブール値の"true"で初期化しておく。
その後変数$iがインクリメントされるタイミングで$bのブール値を反転させている。
同じ出力になるはずだ。
上のような書き方でもいいのだがもう少し短く書けないだろうか?
三項演算子を使えば以下のようにループの中を1行で書く事が出来る

for ($i = 0, $b = true; $i < $names_size; $i++, $b = !$b) {
    printf("<li%s>%s</li>\n", $b ? ' class="foo"': ' class="bar"', $names[$i]);
}

ここではprintf関数を使っているがechoでも出来なくはない。
三項演算子は値を返してくれるのでそのまま出力に渡す事も出来る。

$answer = true;
echo $answer ? "正解": "ハズレ";

"正解"と表示される。

Pythonには長らく三項演算子が存在しなかったがバージョン2.5からサポートされるようになったようだ。
ただし書き方が他の言語とは違って

result = (条件が真の場合の値) if (条件式) else (条件が偽の場合の値)

こんな書き方だ。
PHPと同じ例を使うと

li = ["Tatsunori", "Koji", "Greisinger", "Hisanori", "Nomaguchi"]
for i, value in enumerate(li):
    print "<li%s>%s</li>" % (' class="foo"' if i % 2 == 0 else ' class="bar"', value)

これで同様の出力は得られる。
Pythonは式を書くところが結構限られているので値を返す三項演算子は何かと重宝するかもしれない。
ただこれと同じような事は実際はバージョン2.5以前から出来てはいた。
書き方はこうなる。

for i, value in enumerate(li):
    print "<li%s>%s</li>" % (i % 2 == 0 and ' class="foo"' or ' class="bar"', value)

最初に条件式を書いておいてその値が真であればそのあとのandが実行されその値が返る。
偽になったらその後のorが実行されそちらの値が返る。
みたいな感じだ。
上のような例の場合は問題ないのだがこの

a and b or c

という書き方はちょっとした落とし穴がある。
aがTrueの時bを実行するがもしbがFalseだと常にcが戻る・・という非常に分かりにくい表現になってしまうが。
万全を期すなら以下のように書くといい

for i, value in enumerate(li):
    print "<li%s>%s</li>" % ((i % 2 == 0 and [' class="foo"'] or [' class="bar"'])[0], value)

Pythonでは空の文字列や空のリストはFalseになるがFalseの要素が一つ入ったリストはTrueになる。
という事だ。

カテゴリ:

トラックバック(0)

トラックバックURL: http://blog.beanz-net.jp/beanz_mtos/mt-tb.cgi/23

コメントする