PHPのshuffle()が連想配列では使えない件について

↓こんな連想配列があったとして、
$AmericanLeagueEastDivisionTeams = array(
    'BAL' => array('city' => 'Baltimore', 'name' => 'Orioles'),
    'BOS' => array('city' => 'Boston', 'name' => 'Red Sox'),
    'NYY' => array('city' => 'New York', 'name' => 'Yankees'),
    'TB' => array('city' => 'Tampa Bay', 'name' => 'Rays'),
    'TOR' => array('city' => 'Toronto', 'name' => 'Blue Jays'),
);

shuffle()してみると…
shuffle($AmericanLeagueEastDivisionTeams);
var_export($AmericanLeagueEastDivisionTeams);
↓結果(見やすいように整形済み)
array (
  0 => array ('city' => 'Boston', 'name' => 'Red Sox'),
  1 => array ('city' => 'Toronto', 'name' => 'Blue Jays'),
  2 => array ('city' => 'New York', 'name' => 'Yankees'),
  3 => array ('city' => 'Tampa Bay', 'name' => 'Rays'),
  4 => array ('city' => 'Baltimore', 'name' => 'Orioles')
)
はい。キーが破棄されて、数字キーに割り当て直されちゃいます。

じゃあ、array_rand()でランダム順のキーを取得しよう、と思った。
$len = count($AmericanLeagueEastDivisionTeams);
$abbrs = array_rand($AmericanLeagueEastDivisionTeams, $len);
var_export($abbrs);
↓結果
array (
  0 => 'BAL',
  1 => 'BOS',
  2 => 'NYY',
  3 => 'TB',
  4 => 'TOR',
)
よし、この「キーがランダム順に入った配列」を使おう。
…あれ?並べ変わってなくね?
たまたまかな(^o^;

再実行→やっぱりおんなじ→再々実行→やっぱりおんなじ→(無限ループ)
全件取得する場合は並べ換えて紅の豚?
マニュアルに書いといてよ。そんなこと。。

まあ、array_keys()を使ってそれをshuffle()すれば同じ事はできるか。
$abbrs = array_keys($AmericanLeagueEastDivisionTeams);
shuffle($abbrs);
var_export($abbrs);
↓結果
array (
  0 => 'NYY',
  1 => 'BOS',
  2 => 'TB',
  3 => 'BAL',
  4 => 'TOR',
)
当然ながらうまくいく。再実行すればまた並び変わる。

せっかくだから、関数化しておくか。
PHPオリジナルの命名則にあわせて、ashuffle()と名付ける(※)。
オリジナルのshuffle()が並べ替えが成功したかどうかを返しているので、とりあえずtrueを返すことにする。
function ashuffle(&$array) {
    $keys = array_keys($array);
    shuffle($keys);

    $res = array();
    for ($i = 0, $_l = count($keys); $i < $_l; $i++) {
        $res[$keys[$i]] = $array[$keys[$i]];
    }

    $array = $res;
    return true;
}

これで、
ashuffle($AmericanLeagueEastDivisionTeams);

$rank = 0;
foreach ($AmericanLeagueEastDivisionTeams as $abbr => $team) {
    printf("%d: %s %s (%s)¥n", ++$rank, $team['city'], $team['name'], $abbr);
}
↓結果

1: New York Yankees (NYY)
2: Baltimore Orioles (BAL)
3: Tampa Bay Rays (TB)
4: Boston Red Sox (BOS)
5: Toronto Blue Jays (TOR)
成功。


※:蛇足。
この記事を書く時に、そういえば、もうすでに誰かが作ってるよな。"ashuffle()"って名前で。
っと思ってググってみたら、どうやら無いみたい。。
ってことは、このページがひっかかるようになるんだ。ウシシ( ̄ー ̄)

PHP

— posted by たか at 12:12 am   pingTrackBack [0]

PHPSESSIDの無限ループ

Cookieが無効な環境のために、PHPのセッションID(デフォルトで"PHPSESSID")をURLに(クエリストリングとして)くっつけてリダイレクトする。
ということはモバイル向けサービスで良くあることだと思う。
んで、ローカルでテスト中、件の無限ループが発生した。
apacheのアクセスログを見ると、
hoge.php?foo=var
hoge.php?foo=var&amp;PHPSESSID=(SSID1)
hoge.php?foo=var&amp;amp;PHPSESSID=(SSID1)&amp;PHPSESSID=(SSID2)
...
hoge.php?foo=var&amp;amp;amp;amp;amp;amp;PHPSESSID=(SSID1)&amp;amp;amp;amp;amp;PHPSESSID=(SSID2)&amp;amp;amp;amp;PHPSESSID=(SSID3)&amp;amp;amp;PHPSESSID=(SSID4)&amp;amp;PHPSESSID=(SSID5)&amp;PHPSESSID=(SSID6)
...

すなわち、
hoge.php?foo=var
にアクセスがあって、セッションIDがついてないのでつけましょう。そしてリダイレクト。
hoge.php?foo=var&amp;PHPSESSID=(SSID1)
おやおや、セッションIDがついてないのでつけましょう。そしてリダイレクト。
hoge.php?foo=var&amp;amp;PHPSESSID=(SSID1)&amp;PHPSESSID=(SSID2)
っという具合に、無限に繰り返し、URL長エラーになるまで繰り返してた。っということ。

原因は、"&"であるべきセパレータが"&amp;"になっていること。
"PHPSESSID"のつもりが、"amp;PHPSESSID"になっちゃったわけだ。

さて、誰の仕業だろう?
プログラムで発行しているときにやっちまった?
Net_URLを使ってるから、この子のせい?
PHPが自動で付けたもの?
Apacheが変換した?

とまあ、色々調べてしまったよ。
結論を言うのは簡単だなぁ。。
その結論とは、
PHPの設定がヘンだった。それと、PHPの設定をNet_URLが忠実に読み込んでいたから。

Net_URL::getQueryString()で、クエリストリングのセパレータを、ini_get('arg_separator.output')で取ってきてます。

んで、オイラのWindowsなxampp環境では、php.iniファイルで下記の通り指定していた。
arg_separator.output = "&amp;"


むむむ。なんでこんなことしたんだっけ?
はい。これをコメントアウトして、サービスを再起動すると、…ちゃんと動いた。


以下、苦労した原因を箇条書きしておく。繰り返さないように(´・ω・`)
・デバッグ用にリダイレクトURLをHTML出力してみたわけだが、<textarea>タグ内ならば生のソースが表示されるハズ、と初歩的な勘違い
  → "&"と表示されて、うーん、ここまでは上手く行ってるのに…と誤解。実際は"&amp;"だったのに
・php.iniを書き換えたら即時適用されそうな気がしていた
  → apacheを最起動しないと読まないよ。Windowsの場合サービスの再起動が必要。
・php.iniを変更するなら、なぜそうしたかメモっておこうよ。。
・グーグル先生を過信し過ぎ(←あえて冗長表現してみた)。

PHP

— posted by たか at 03:27 pm   pingTrackBack [0]

 

BroadcastReceiverが勝手に止まってしまう件について

BroadcastReceiverを使って、ほとんどすべてのブロードキャストを受け取ってToastでポップアップ表示する。
という、うっと惜しい(なぜか変換できない)Widgetを作ってみたLink わけだが、いつの間にか勝手に泊まる。いや、止まる。

さて、グーグル先生に相談だ(音符

BroadcastReceiverに寿命があって、寿命が尽きたことを知る手段でもあるのではないかと探したんだけど、うまくいかない。
んで、それは置いておいて、別件でサービスについて調べてたんだけど、
…これは、という情報があった。

こちらに曰く、

Android は、メモリが少なくなってくると...サービスも止められてしまうことがある
...
システムがサービスを停止させた場合、メモリに余裕が出来るとシステムが再度起動してくれる
ああ、そんなこと聞いたことある。聞いたんじゃなくて読んだんだけど。<どうでもいいだろ

システムから起動された時は Service::onStart は呼ばれず、Service::onCreate までしか呼ばれない
これだ(゚∀゚)!
確かに、ServiceのonStartでBroadcastReceiverをregisterReceiverしておった。
onCreateでレジストしてもよかろうもんがじゃ。
これで、止まっても復活してくれるのかなぁ。

やってみるけど、いつ勝手に止まるか、そしていつ再起動するかがわからないから、テストがムズイね┐(´д`)┌

ウィジェット アンドロイド

— posted by たか at 12:15 am   pingTrackBack [0]

T: Y: ALL: Online:
ThemeSwitch
Created in 0.2814 sec.
prev
2011.10
next
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
 
blogBar
Firefox3 Meter