読者です 読者をやめる 読者になる 読者になる

memo-pad’s blog

自分のためのメモをまとめています。ここに書いてある内容については責任は負いません。全て自己責任でお願いします。

phpのcodegolf Tips

先日、身内でCodegolfをやったので、その時に学んだショートコーディングの知識をメモ

Codegolfというのは如何に文字数を少なくコードを記述するかを競う競技です。
コードゴルフ - Wikipedia

それではTipsのメモを書いていきます。

出力に改行を出したいときには\nは使わない

例えばこんなコード

echo "test\n";

こう書けば1文字少なくできます(改行分は1文字扱いのため2文字削減にはならない)

echo "test
";

関数にエイリアスがないかを確認する

例えば配列を結合して文字列にしたいときに下記のようにimplodeを使いますよね?

implode($array);

実はimplodeにはjoinというエイリアスが設定されているので、下記のように変更可能です。

join($array);

これだけで3文字分削減です。

ちなみにphpエイリアスhttp://php.net/manual/ja/aliases.phpに載っています。

foreachのas前後のスペースを削る

例えば通常だと下記のようにforeachを記述すると思います。

foreach($a as $b){}

しかし、実は下記のようにasと$bがくっついていても問題ありません。

foreach($a as$b){}

また、先頭が配列形式だったり、カッコがある場合はこんな風にくっつけても問題ないです。

foreach($a[0]as$b){}
foreach(explode(',',$a)as$b){}

要するにちゃんとパースしてくれそうな形式ならas前後にスペースはいらないということですね。

可変変数を使う

可変変数の詳しい説明はこちらPHP: 可変変数 - Manual

例えばa,b,cという文字が出現する回数を数える場合、普通ならこんな感じにかけます。

for(;$i=fgetc(STDIN);){++$a[$i];}
foreach(str_split("abc")as$v){echo $a[$v];}

ここで可変変数を使うとこうかけたりします。

for(;$i=fgetc(STDIN);){++$$i;}
foreach(str_split("abc")as$v){echo $$v;}

可変変数は使い方によっては結構文字数減らせるので面白いです。

echoする際には""をのぞける場合もある

例えば下記のようなコードは、

echo "test";

このように書き直すことができます。

echo test;

これは、phpの未定義の定数を使用した際の挙動を利用したものです。

詳しくはこちらPHP: 構文 - Manual

可変関数を使う

可変変数の次は可変関数です。

こちらは複数回同じ関数を使う際に有効になります。

可変関数の詳しい説明はこちらPHP: 可変関数 - Manual

例えばこんな感じで同じ関数を使用するとき

echo implode($a);
echo implode($b);
echo implode($c);
echo implode($d);
echo implode($e);

可変関数を使うと結構文字数を削減できます。

$i=implode;
echo $i($a);
echo $i($b);
echo $i($c);
echo $i($d);
echo $i($e);

ただ、実際は同じ関数使う部分は極力一か所にまとめたりするので、可変関数は使う機会が限られるかもしれません。

phpのショートタグを使う

通常php

<?php echo "test";

というコードは、

<?="test";

というように書くことができます。

一番最初にforなどの制御構造が来てしまう場合は使うのは難しいですが、使える状況だと結構削れます。

終わりに

他にも色々あった気がするのですが、今のところぱっと思い出せるのがこれくらいなので、思い出し次第適宜追記していきたいと思います。

codegolfをやってみると、今まで知らなかった言語の仕様なども知れるので、初めて触る言語の勉強にもちょうどいいと思います。

ということで、一緒にcodegolfやりましょう

rubyの勉強始めました

個人的に気になった特徴

  • 末尾にセミコロン(;)が不要

文字出力(print, puts, p)

  • Objectを文字列として出力する
    • print
    • puts
      • 改行が付与される
    • p
      • デバッグ用に使われる
      • オブジェクトの形式を含め表示

# コード
array = ['test1','test2','test3']

print array
puts array
p array

# 出力結果
test1test2test3test1
test2
test3
["test1", "test2", "test3"]
  • 上記のようにputsでは配列の要素1つ1つに対して改行が付与されていることがわかる
    • ハッシュに対しては特に要素毎の改行はされなかった

配列

定義

array = ['test1','test2','test3']

# コード
array = ['test1','test2','test3']
p array[0]     # 0番目、つまりtest1
p array[-1]    # 後ろから1番目、つまりtest3
## 要素の呼び出しは範囲でも可能
p array[0..2]  # 0から2まで
p array[0...2] # 0から1まで(2を含まない)

# 出力結果
"test1"
"test3"
["test1", "test2", "test3"]
["test1", "test2"]

ハッシュ

定義

hash = {"test1" => 10, "test2" => 20, "test3" => 30}

キーにシンボルというものを使って、下記のように表記することも可能(文字列キーよりアクセスが早い)

hash_symbol = {:test1 => 10, :test2 => 20, :test3 => 30}

また、シンボルは次の様に省略して記述可能(ruby1.9からサポート)

hash_symbol2 = {test1: 10, test2: 20, test3: 30}

# code
hash = {"test1" => 10, "test2" => 20, "test3" => 30}
p hash
hash_symbol = {:test1 => 10, :test2 => 20, :test3 => 30}
p hash_symbol
hash_symbol2 = {test1: 10, test2: 20, test3: 30}
p hash_symbol2

# 出力結果
{"test1"=>10, "test2"=>20, "test3"=>30}
{:test1=>10, :test2=>20, :test3=>30}
{:test1=>10, :test2=>20, :test3=>30}
  • ruby2.2.4でpで出力すると省略して記述したものも、通常のシンボルでの表記で出力された

javascriptのコールバック関数

javascriptの勉強はじめました。

いきなりコールバック関数ってなんじゃこれという感じになったので、今わかってる範囲内でメモ。

下記のように、test1のcallback(‘aaa’, ‘bbb’)がtest2の引数a,bにそれぞれ渡される挙動をするのがコールバック関数。

function test1(callback) {
    callback('aaa', 'bbb');
}

function test2(a, b) {
    console.log(a + "," + b);
}

test1(test2);

使い所としては、非同期の場合に処理の順序を制御する場合など。

例えばこれだと出力はfugaとなり想定通りなものとなる。

function test1(hoge) {
    hoge = 'fuga';
    return hoge;
}

function test2(hoge) {
    console.log(hoge);
}

var hoge = 'hoge';
test2(test1(hoge));

出力:fuga

一方で非同期なため、下記のようにtest1で時間をかけてしまうとfugaに文字列がセットされる前にtest2が走ってしまいundefinedとなってしまう。

function test1(hoge) {
    setTimeout(function () {
        hoge = 'fuga';
        return hoge;
    }, 1000);
}

function test2(hoge) {
    console.log(hoge);
}

var hoge = 'hoge';
test2(test1(hoge));

出力:undefined

そこでコールバック関数を使って制御をしてあげるとちゃんと出力がfugaとなる。

function test1(callback) {
    var hoge = 'hoge';
    setTimeout(function () {
        hoge = 'fuga';
        callback(hoge)
    }, 1000);
}

function test2(hoge) {
    console.log(hoge);
}

test1(test2);

出力:fuga

それにしても、時間かけるようにするためsleep関数とかないかなーと思ったのですが、javascriptってsleep関数ないのですね……

docomo端末でのMVNOテザリング有効化方法

導入

だいぶ前に手に入れた0sim(0 SIM | nuroモバイル)を長らく放置していたので、余っていたDocomo端末にさしてモバイルルータ代わりにしました。

月500MBまでしか無料じゃないですけど、そこまで頻繁には使わないので中々快適です。

ただ、Docomo端末でMVNOを使ってテザリングする際に罠が一つあったのでここに書いておきます。

ちなみにメインで使ってるau端末はMVNO使ってますがテザリングはそのまま使えたのでdocomo端末特有の問題だと思われます。

どんな罠があるのか?

結論から言ってしまうと、Docomo端末でMVNO使ってテザリングするとネットに繋がりません。

これは、テザリングする際にDocomo端末はデフォルトのAPNを見にいってしまって、MVNO用に設定したAPNを見に行かないのが原因みたいです。

どうやってテザリング中にネット接続をできるようにするのか

まずはadb使えるように環境を整える必要があります。

自分はMac環境ですが、Android Studioを入れていたため既にadbが入っている状態でしたので、ここは省略

下記は実際に自分の持っている端末(Docomo L-05D)に対して行ったことです。

  1. PCでadbを使える環境を整える
  2. スマートフォンをUSBデバッグ状態でPCと接続する
  3. コマンドプロンプトやターミナルで下記コマンドを実行(L-05Dの場合)
$ adb shell content insert --uri content://settings/secure --bind name:s:tether_dun_required --bind value:i:0

–bind value:i:に0を指定することでテザリング時にAPNが変更されなくなります。

もとに戻したい時はここの0を1にすればOK。

PCとスマートフォンを接続するケーブルは給電専用ではなくて、下記のようなデータ通信可能なケーブルを使ってください

補足: adb contentコマンドの使い方

下記コマンドでcontentコマンドの使い方が見れる

$ adb shell content

出力結果

usage: adb shell content [subcommand] [options]

usage: adb shell content insert --uri <URI> --bind <BINDING> [--bind <BINDING>...]
  <URI> a content provider URI.
  <BINDING> binds a typed value to a column and is formatted:
  <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:
  <TYPE> specifies data type such as:
  b - boolean, s - string, i - integer, l - long, f - float, d - double
  Note: Omit the value for passing an empty string, e.g column:s:
  Example:
  # Add "new_setting" secure setting with value "new_value".
  adb shell content insert --uri content://settings/secure --bind name:s:new_setting --bind value:s:new_value

usage: adb shell content update --uri <URI> [--where <WHERE>]
  <WHERE> is a SQL style where clause in quotes (You have to escape single quotes - see example below).
  Example:
  # Change "new_setting" secure setting to "newer_value".
  adb shell content update --uri content://settings/secure --bind value:s:newer_value --where "name='new_setting'"

usage: adb shell content delete --uri <URI> --bind <BINDING> [--bind <BINDING>...] [--where <WHERE>]
  Example:
  # Remove "new_setting" secure setting.
  adb shell content delete --uri content://settings/secure --where "name='new_setting'"

usage: adb shell content query --uri <URI> [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]
  <PROJECTION> is a list of colon separated column names and is formatted:
  <COLUMN_NAME>[:<COLUMN_NAME>...]
  <SORT_OREDER> is the order in which rows in the result should be sorted.
  Example:
  # Select "name" and "value" columns from secure settings where "name" is equal to "new_setting" and sort the result by name in ascending order.
  adb shell content query --uri content://settings/secure --projection name:value --where "name='new_setting'" --sort "name ASC"

phpのin_array, array_key_exists, issetの速度比較

phpのバージョンは5.6.29

実行結果

$ php isset.php 
isset
5.6982040405273E-7seconds

$ php array_key_exists.php 
array_key_exists
1.3089179992676E-6seconds

$ php in_array.php 
in_array
0.011404228210449seconds

$ php or.php 
||
0.028414559364319seconds

速さはisset, array_key_exists, in_array, 論理演算子の順番で大体イメージ通りの結果になりました。
やっぱりissetやarray_key_existsと比較するとin_arrayは遅いですね。
ただ、issetとarray_key_existsはin_arrayと違ってkeyに対して探索行わせるので、そのために下記のように毎回array_flip噛ませるとかやってると逆に遅くなって本末転倒なので注意

$ php isset_flip.php
isset_flip
0.059537370204926seconds

$ php array_key_exists_flip.php
array_key_exists_flip
0.058682680130005seconds

今回のコード

github.com

isset.php
<?php
$search_number = 99999;
$list = range(0, 99999);
$loop_count = 100;

echo "isset\n";
$start_time = microtime(true);
for ($i=0; $i<$loop_count; $i++) {
    if (isset($list[$search_number])) {}
}
$time = microtime(true) - $start_time;
echo $time/$loop_count . "seconds\n";
array_key_exists.php
<?php
$search_number = 99999;
$list = range(0, 99999);
$loop_count = 100;

echo "array_key_exists\n";
$start_time = microtime(true);
for ($i=0; $i<$loop_count; $i++) {
    if (array_key_exists($search_number, $list)) {}
}
$time = microtime(true) - $start_time;
echo $time/$loop_count . "seconds\n";
in_array.php
<?php
$search_number = 99999;
$list = range(0, 99999);
$loop_count = 100;

echo "in_array\n";
$start_time = microtime(true);
for ($i=0; $i<$loop_count; $i++) {
    if (in_array($search_number, $list, true)) {}
}
$time = microtime(true) - $start_time;
echo $time/$loop_count . "seconds\n";
or.php
<?php
$search_number = 99999;
$list = range(0, 99999);
$loop_count = 100;

echo "||\n";
$start_time = microtime(true);
for ($i=0; $i<$loop_count; $i++) {
    if ($search_number === 0 ||
        $search_number === 1 ||
〜〜〜〜〜〜〜〜〜〜〜〜〜略〜〜〜〜〜〜〜〜〜〜〜〜〜
        $search_number === 99999) {}
    }
$time = microtime(true) - $start_time;
echo $time/$loop_count . "seconds\n";
isset_flip.php
<?php
$search_number = 99999;
$list = range(0, 99999);
$loop_count = 100;

echo "isset_flip\n";
$start_time = microtime(true);
for ($i=0; $i<$loop_count; $i++) {
    $flipped_list = array_flip($list);
    if (isset($flipped_list[$search_number])) {}
}
$time = microtime(true) - $start_time;
echo $time/$loop_count . "seconds\n";
array_key_exists_flip.php
<?php
$search_number = 99999;
$list = range(0, 99999);
$loop_count = 100;

echo "array_key_exists_flip\n";
$start_time = microtime(true);
for ($i=0; $i<$loop_count; $i++) {
    $flipped_list = array_flip($list);
    if (array_key_exists($search_number, $flipped_list)) {}
}
$time = microtime(true) - $start_time;
echo $time/$loop_count . "seconds\n";