忍者ブログ
[PR]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。



2025/04/16 06:36 |
PHPでLINQ
PHPでLINQを再現するライブラリ、GINQを試してみます。

そもそもLINQって何よ。
http://ja.wikipedia.org/wiki/%E7%B5%B1%E5%90%88%E8%A8%80%E8%AA%9E%E3%82%AF%E3%82%A8%E3%83%AA
> データ集合に対して標準化された方法でデータを問い合わせることを可能にする
http://msdn.microsoft.com/ja-jp/library/bb308959.aspx
> .NET Framework に汎用クエリ機能が追加され、リレーショナル データや XML データだけでなく、あらゆる情報ソースにクエリ機能が適用されます。

何のこっちゃ。
平たく言うと、配列やらオブジェクトやらその他諸々の集合に対してSQL(っぽいもの)でSELECTできちまうぜ、という代物らしい。
さっそく試してみましょう。
<?php
	
	// Ginq
	require_once('path/to/ginq/Ginq.php');
	
	$sample1 = ['John', 'Peter', 'Joe', 'Patrick', 'Donald', 'Eric', 'Joe'];
	
	// SELECT name FROM sample1 WHERE LENGTH(name) < 5
	$under5 = Ginq::from($sample1)
		->where(function($name){return strlen($name) < 5;})
		->toArray();
	
	// SELECT DISTINCT name FROM sample1 ORDER BY id DESC
	$reverse = Ginq::from($sample1)->reverse()->distinct()->toArray();
	
	// Employee PHPLinqのサンプルのコピペ
	class Employee {
		public $Id, $DepartmentId, $ManagerId, $Name, $Email, $Age;
		public function __construct($id = 0, $departmentId = 0, $managerId = 0, $name = '', $email = '', $age = '') {
			$this->Id				= $id;
			$this->DepartmentId 	= $departmentId;
			$this->ManagerId 		= $managerId;
			$this->Name 			= $name;
			$this->Email 			= $email;
			$this->Age				= $age;
		}
	}
	$employees = [
		new Employee(1, 1, 5, 'Maarten', 'maarten@example.com', 24),
		new Employee(2, 1, 5, 'Paul', 'paul@example.com', 30),
		new Employee(3, 2, 5, 'Bill', 'bill.a@example.com', 29),
		new Employee(4, 3, 5, 'Bill', 'bill.g@example.com', 28),
		new Employee(5, 2, 0, 'Xavier', 'xavier@example.com', 40)
	];
	
	// SELECT Email, SUBSTR(Email, INSTR(Email,'@')+1) FROM employees WHERE LENGTH(Name) = 4 ORDER BY Age DESC LIMIT 2 OFFSET 1
	$result = Ginq::from($employees)
		->where(function($employee){ return strlen($employee->Name) === 4; })
		->orderByDesc(function($employee){ return $employee->Age; })
		->drop(1)->take(2)
		->select(function($employee){ return [
			'EmailAddress' => $employee->Email,
			'Domain' => substr($employee->Email, strpos($employee->Email, "@") + 1)
			]; })
		->toArray();
コメントで書かれているSQLとほぼ同じ処理を、メソッドチェーンでSQLっぽく書くことができるようになりました。
SQLそのものではありませんが、同じようなかんじで使えます。
いちいちarray_filter()してforeachで抽出して、といった面倒な処理を書かなくて済みます。

前回のPHPLinqとほぼ同じですが、fromがIteratorに対応しているため、ArrayObjectやSPLなんかも突っ込めます。
また大抵のメソッドがcallableを受け取れるので、文字列で書かなければいけないPHPLinqより楽で汎用性があります。

まあ、このスライド見ればGinqの機能はだいたいわかります。
今回は使ってませんが、集計とかJOINとか他にもたくさん機能があり、また遅延実行にも対応しててパフォーマンスもよさげ。
けっこう使い勝手の良さそうなライブラリです。
PR


2014/06/23 23:12 | Comments(0) | PHP
スターマイン主要キャラ二人称リスト Ver0.1
スターマイン主要キャラ二人称リスト Ver0.1。

→呼ばれる
↓呼ぶ
行成風見叶得里梨牧乃雪華志染小原山中吉尾二階堂優雅二階堂秀治古川いより石橋友香桑畑店主州弘奈美子伊塔志穂香
行成 風見
風見さん
お嬢さん
郷ちゃん
郷ちゃんサン
叶得さん
叶得ちゃん
かな得さん
繭ちゃん
マユちゃん
里梨
里梨さん
里梨サン
さとりサン
お父さん
里梨クン
牧乃さん
牧乃サン

潮さん
潮サン
雪華さん 鈴ちゃん
鈴ねえちゃん
志染さん
志染監督
七海さん 小原君 山中 吉尾
巧くん
二階堂先輩
部長さん
会長さん 古川さん
よりりん
  桑畑 オッサン 先生 親父
お父様
先輩
風見 行成
あ・な・た

風見さん

あんた
叶得 里梨 牧乃 雪華
リン
志染 小原君
小原クゥン
  吉尾君 優雅さん                
ゆーくん
おとうさん
カザミ
風見先生
わたし
郷ちゃん
カナ
叶得
マユ サトリ
里梨
マキさん
まきさん
お前
せっちゃん
セッちゃん
リン 志染 七海さん 小原君 山中さん                 お父様  
叶得 行成君
ゆーきーなーりーくーん
お兄ちゃん♪
風見 里梨 牧乃 志染 七海さん
透さん
小原君     先輩             お父様  
行成さん 風見さん 郷さん 叶得さん 里梨さん 牧乃さん 潮ちゃん 雪華さん 志染さん 七海さん     吉尾さん     いよりちゃん ゆかちー       お父様
十口先生
 
里梨 行成
お前
行成先生
風見
お前
叶得
みゃうちゃん
お前
あたし 牧乃
牧乃様
雪華 志染
お前
七海
小原 山中   二階堂サン                
牧乃 ユキ君
ユキくん
風見ちゃん 郷ちゃん カナちゃん 繭ちゃん 里梨ちゃん
牧乃お姉さん
潮ちゃん 雪華ちゃん 鈴ちゃん 志染さん
園長先生
七海ちゃん 小原君   吉尾君               お義父様  
ユッキー 風見 叶得
マユ
里梨 まきちん
マキちん
牧乃様
あたし せっちゃん 志染 ななみん 小原っち         よりりん            
雪華 ユキ 風見 叶得 七海     吉尾 優雅                
お兄ちゃん
ゆーちゃん
行成君
お姉ちゃん
風見お姉ちゃん
郷ちゃん カナちゃん 繭ちゃん
みゃうちゃん
里梨ちゃん 牧お姉ちゃん
牧おねえちゃん
うしちゃん せっちゃん わたし 志染さん ななみちゃん
透ちゃん
    優雅ちゃん                 シホちゃん
志染 貴方 風見
この子
貴女
貴女
里梨
お父さん
牧乃
貴女
牧お姉ちゃん

貴女
雪華 透さん 店主 親御さん
陸田君
陸田くん
風見さん 叶得さん 繭ちゃん 星野さん 牧乃さん 潮ちゃん 雪華先輩 鈴先輩 天見さん 山中さん 吉尾くん
小原 陸田君         里梨さん 星野さん         吉尾くん             州弘先生    
山中加代子 陸田君 風見さん
風見ちゃん
郷さん     里梨さん                              
吉尾 陸田           星野さん
牧乃さん
  雪華さん   天見さん
志染さん
七海     二階堂
生徒会長
             
二階堂優雅 陸田さん     叶得さん   星野さん     雪華さん 鈴さん                     志穂香さん
二階堂秀治           星野君
キミ
            吉尾                
古川いより 陸田先輩
先輩
      繭ちゃん     潮ちゃん               ゆかちー          
石橋友香         繭っち     うっしー                          
桑畑 陸田
陸田サン
                  七海                      
ラーメン屋                     志染ちゃん                      
州弘奈美子 陸田                                        
伊塔志穂香 陸田君         里梨さん       鈴ちゃん                      
※単行本1~5巻。ドラマCDやその他媒体は対象外。
※2話以上に登場するキャラを主要キャラとする。
※父以外は二人称のみ。

見直しすらしていないのでおそらく抜けがあります。
見落としがあったら教えてください。


2014/06/22 23:37 | Comments(0) | その他
買ったものリスト 2014/06/22
湯長谷藩の藩主、内藤政醇は参勤交代から帰ってきたばかりのところを、突然再びの参勤交代を言い渡される。
通常なら10日はかかるところ、期限は僅か5日。
貧乏な弱小藩には路銀すらなく、通常の参勤交代すら不可能な状態だった。
きちんと格を示しつつ期日までに江戸に上がらねば、お取り潰しどころか処刑すらもありうる。
裏には老中の一人が暗躍しており、あの手この手で邪魔をしてくる。
果たして彼らの運命や如何に。

イオンモールむさし村山に居たところ、たまたまタイムラインで超高速!参勤交代の
話が上がってたので見てきました。
座席は9割くらい。

粗筋だけだととても暗い話にしか思えませんが、タイトルからして超とか!とか時代劇としてはおかしい表現が入っています。
実際ツッコミどころしか見当たらない、実にバカバカしい(褒め言葉)作品でした。
最初に上映中は静かにしろって言われますが、本作では無理です。
周囲からも何度も笑いが上がっていました。
白昼忍者軍団と集団戦とか一体どうすんだそれ。
あと伏線は概ね回収するのですが、身分の話はそれ解決になってるのか。
もっとも笑いどころだけではなく、シリアスだったり深刻だったりするところも多々あり、それらがハーメルンのバイオリン弾き(原作)のように混ざり合って描写されます。

歴史に厳格な人は絶対受け付けられないと思いますが、単純に娯楽として見るにはなかなか楽しい作品でした。
最後のオチも明るくて清々しい。

で、結局財政難はどうなったんだ。



アホガール1 ヒロユキ
アホガール2
アホガール3
☆☆☆

実に清々しくアホだ。
看板に偽りなし。
何一つ深いことのない単純娯楽アホ話。
つうか妹のほうが深刻だな。


きしとおひめさま1 パイン
☆☆☆

すこしふしぎな世界の日常ものかと思ったら鎧の騎士とか現われて一体なんなんだこれ。
1巻のほとんどが序章で、まだ話の展開を広げることすらできていない状態で、登場人物も誰が誰やらです。
もうしばらく続きを見ないと評価を下せないような雰囲気ですが巻を買うかどうか微妙なところ。


絶対☆霊域7 吉辺 あくろ
☆☆☆☆☆

ヒナちゃんがかわいいだけの漫画。
ヒナちゃんの魅力だけでいまだに引っ張られる。
最後の人は8巻で出てこなかったな。どうなってんだ。


2014/06/22 17:25 | Comments(0) | 買ったもの
PHPでLINQ
PHPでLINQを再現するライブラリ、PHPLinqを試してみます。

そもそもLINQって何よ。
http://ja.wikipedia.org/wiki/%E7%B5%B1%E5%90%88%E8%A8%80%E8%AA%9E%E3%82%AF%E3%82%A8%E3%83%AA
> データ集合に対して標準化された方法でデータを問い合わせることを可能にする
http://msdn.microsoft.com/ja-jp/library/bb308959.aspx
> .NET Framework に汎用クエリ機能が追加され、リレーショナル データや XML データだけでなく、あらゆる情報ソースにクエリ機能が適用されます。

何のこっちゃ。
平たく言うと、配列やらオブジェクトやらその他諸々の集合に対してSQL(っぽいもの)でSELECTできちまうぜ、という代物らしい。
さっそく試してみましょう。
<?php
	
	// Linq include_path設定が必要
	set_include_path(get_include_path() . PATH_SEPARATOR . 'path/to/phplinq/Classes');
	require_once 'path/to/phplinq/Classes/PHPLinq/LinqToObjects.php';
	
	$sample1 = ['John', 'Peter', 'Joe', 'Patrick', 'Donald', 'Eric', 'Joe'];
	
	// SELECT name FROM sample1 WHERE LENGTH(name) < 5
	$result = from('$name')->in($sample1)
		->where('strlen($name) < 5')
		->select('$name');
	
	// SELECT DISTINCT name FROM sample1 ORDER BY id DESC
	$result = from('$name')->in($sample1)->reverse()->distinct('$name')->select();
	
	// Employee サンプルのコピペ
	class Employee {
		public $Id, $DepartmentId, $ManagerId, $Name, $Email, $Age;
		public function __construct($id = 0, $departmentId = 0, $managerId = 0, $name = '', $email = '', $age = '') {
			$this->Id				= $id;
			$this->DepartmentId 	= $departmentId;
			$this->ManagerId 		= $managerId;
			$this->Name 			= $name;
			$this->Email 			= $email;
			$this->Age				= $age;
		}
	}
	$employees = [
		new Employee(1, 1, 5, 'Maarten', 'maarten@example.com', 24),
		new Employee(2, 1, 5, 'Paul', 'paul@example.com', 30),
		new Employee(3, 2, 5, 'Bill', 'bill.a@example.com', 29),
		new Employee(4, 3, 5, 'Bill', 'bill.g@example.com', 28),
		new Employee(5, 2, 0, 'Xavier', 'xavier@example.com', 40)
	];
	
	// SELECT Email, SUBSTR(Email, INSTR(Email,'@')+1) FROM employees WHERE LENGTH(Name) = 4 ORDER BY Age DESC LIMIT 2 OFFSET 1
	$result = from('$employee')->in($employees)
		->where('$employee => strlen($employee->Name) === 4')
		->orderByDescending('$employee->Age')
		->skip(1)->take(2)
		->select('new {
			"EmailAddress" => $employee->Email,
			"Domain" => substr($employee->Email, strpos($employee->Email, "@") + 1)
		}');
コメントで書かれているSQLとほぼ同じ処理を、メソッドチェーンでSQLっぽく書くことができるようになりました。
SQLそのものではありませんが、同じようなかんじで使えます。
いちいちarray_filter()してforeachで抽出して、といった面倒な処理を書かなくて済みます。

一見便利ですが、欠点としては、対応しているのが配列とZend_Dbだけという点です。
ソースにはAdapter/MysqliやAdapter/Pdo/Mysqlなんてものがあるので、PDOを突っ込めるのかと思いきや、何故かZend_Db_Adapterを要求されます。
またArrayObjectなんてほぼ配列なのですが、これも対応していません。
サンプルではRSSのXMLを処理している例も載っているのですが、単にSimpleXMLElement::xpath()で配列にしてから突っ込んでるだけでした。
対応がもっと広がればどんどん便利になるかと思われましたが、2009年あたりで開発が停止しています。
残念。


2014/06/20 22:55 | Comments(0) | PHP
買ったものリスト 2014/06/15

スターマイン4 限定版 ストロマ
スターマイン5 特装版
☆☆☆☆☆

限定版特装版だけカバー違うとかずるい
しかも本体側にそれをネタにした4コマが書かれていたりします。
これがなければわざわざ買うこともなかったのに。
なおドラマCDは聞いていません。


葉月カノンは甘くない。1 コバシコ
☆☆☆

甘いなあ。
甘いねえ。
まったくもって甘くなくなかった。
あと保健教師が普通にクズいんだが大丈夫か。


この麻婆豆腐がすごい 版元ひとり
☆☆☆

市販の麻婆豆腐の素12種類を評価する。
豆腐と挽肉を混ぜて炒めるだけというスーパーとかでよく売ってるあれです。
丸美屋2点、中村屋3点、CookDo3点、他PB商品などを食べ比べています。
結果としてはどれも一定レベル以上に美味しいという、喜ばしいはずなんだけど見てる方としては微妙に残念な結果に。
麻として最も高評価だったのは、ユウキの中華クオリティ四川麻婆ソースでした。
試してみたいところですが今の自宅には冷蔵庫はおろか焜炉すら無い。
なお私は陳麻家によく行っています。
他に四川風麻婆豆腐の店を知らなかったからですが、調べてみたらどうやら新宿野村ビルに陳麻婆豆腐があるらしい。
今度行ってみよう。

モバクソゲー イヴ それいゆ
☆☆☆

煽りに「こうして我が社は株が下落した」とか書いてあるんだが、そのような話は全く無かった。
看板に偽り甚だしい。
当たれば大きいスマホゲーですが、実際は表に出るのは極一部だけで、ほとんどの有象無象はその影で存在も知られないまま消えていきます。
そんなゴミみたいなスマホゲーを色々と紹介したり遊んだ感想とかを記載してくれるクソゲー本です。
ただこの界隈の流行り廃りは家庭用より遥かに早く、かつ形としても残らないので、後から見て共有できるクソゲー体験には絶対になり得ないのは残念です。
マインドシーカーやデスクリムゾンで盛り上がることはあっても、セブンズストーリーやヒロインウォーズとかで話が合うことなんて一生ないでしょう。
そういや私、そもそも根本的にスマホゲーに興味がなかった。


2014/06/15 21:10 | Comments(0) | 買ったもの
「Excel列名変換問題」をPHPで解く
http://blog.jnito.com/entry/20111102/1320253815
http://blog.jnito.com/entry/20111231/1325304733

数値とExcelのA1参照形式を相互変換する問題。

上限無しとかいう制限が入っていますが、とりあえず普通にintの範囲で記述します。
あちらの解答例もint越えを全く考慮してないので特に問題ないでしょう。

<?php
	class EXCEL{
	
		/**
		* Excelの列変換、数値から文字列に
		* @param int 「1」みたいな数値
		* @return String 「A」みたいな文字列
		*/
		public function getStr($input){
			$ret = '';
			do{
				$tmp = gmp_div_qr($input, 26);
				$input = gmp_intval($tmp[0]);
				$amari = gmp_intval($tmp[1]);
				// 割り切れる場合は0ではなく26として扱う
				if($amari === 0){
					$input--;
					$amari = 26;
				}
				$ret .= chr($amari+64);
			}while($input);
			
			return strrev($ret);
		}
		
		/**
		* Excelの列変換、文字列から数値に
		* @param String 「A」みたいな文字列
		* @return int 「1」みたいな数値
		*/
		public function getInt($input){
			$digit = strlen($input)-1;
			$ret = 0;
			for($i=0;$i<=$digit;$i++){
				$ret += (ord($input[$digit-$i])-64) * (26**$i);
			}
			return $ret;
		}
		
	}
	
	// 以下はテスト
	$test = [
		[1, 'A'],
		[2, 'B'],
		[3, 'C'],
		[25, 'Y'],
		[26, 'Z'],
		[27, 'AA'],
		[28, 'AB'],
		[51, 'AY'],
		[52, 'AZ'],
		[53, 'BA'],
		[54, 'BB'],
		[256, 'IV'],
		[16384, 'XFD'],
	];

	$excel = new EXCEL();
	foreach($test as $key=>$data){
		$answer = $excel->getStr($data[0]);
		if($answer !== $data[1]){
			print('えらー');
		}
	}
	foreach($test as $key=>$data){
		$answer = $excel->getInt($data[1]);
		if($answer !== $data[0]){
			print('えらー');
		}
	}

第1問第2問合わせても30分かかりませんでした。
つうか第2問のほうが簡単で5分くらいで終わったんだが。
まあPerlで解けと言われたら解けませんけどね。

考え方は簡単で、単に26で割っていくだけです。
26で割り切れる場合だけ注意が必要ですが、それ以外は単純にchr()で数値文字を変換すればいいです。
逆に数値にする場合は、26の例外すらも一切不要です。
何の問題もなく完成。

しかしまあ$amariはないな。


2014/06/13 23:32 | Comments(0) | PHP
DoctrineのDISTINCTは正しく動作しない
Doctrine_Query::create()->from('HOGE a')->distinct(true)->select('a.fuga');

// Expected result : SELECT DISTINCT fuga FROM hoge.
// Actual result : SELECT DISTINCT id, fuga FROM hoge.
見ての通り、発行されるSQLに勝手にID(主キー)が入るので正しく動作しない。
DISTINCTをselect()内に持ってきたとしても勝手に書き換えられるので駄目。

http://stackoverflow.com/questions/7188219/how-to-select-distinct-query-using-symfony2-doctrine-query-builder
http://www.developpez.net/forums/d793147/php/php-sgbd/orm/doctrine/doctrine-select-distinct/

回避方法は「GROUP BYを使え」らしい。
ふざけてるの?
Doctrine_Query::create()->from('HOGE a')->select('a.fuga')->groupBy(a.fuga);

// SELECT id, fuga FROM hoge group by fuga.
一応想定と同じ結果は取得できるのだが、意味が全く異なるので正しい動作とは言いかねる。

結論
「DoctrineでDISTINCTするときは直接SQL書こう」
Doctrine::getConnectionByTableName('HOGE')->execute('SELECT DISTINCT fuga FROM hoge')->fetchAll();

ところでDISTINCTよりEXISTSの方が早いという記事をよく見かけるんだけど、
結合しないfugaテーブルでEXISTSを使うにはどうすればいいんだろう?


2014/06/09 22:57 | Comments(0) | PHP
買ったものリスト 2014/06/08

スターマイン1 ストロマ
スターマイン2
スターマイン3
スターマイン4
スターマイン5
☆☆☆☆☆

ある日突然10人もの女の子と同居することになり、しかもほぼ全員が主人公にぞっこんというシスプリもびっくりの超展開。
いったいこの展開にどう説得力を持たせるのかと思えば、全員地球外生命体なのだという一言で事なきを得た。

本作やばい。
設定からして死ぬほどよくある萌え4コマかなと思えばそのとおりなのですが、なんか知らんが箱入りドロップス放課後アトリエといろレベルに匹敵するハマりようだ。

ただ、本作も、ふぃっとねすみたいに2巻で終わっていたらここまで評価はしてなかったと思います。
おそらく「登場人物が無駄に多すぎて一人一人を描き切れていない」みたいな。
しかし購入時点で既に5巻出ていたので、十数人という多すぎる登場キャラでも、巻を重ねることでそれぞれの魅力が十分に描かれています。
一読では何がなんだかわからず、読み返してわかるタイプの作品でしょう。

なおお気に入りは志染と牧乃。
次点で風見と雪華と叶得あたりか。
いやあみんな可愛いです。

今後の展開への希望というか妄想。
9巻まで、もしかしたら10巻までは明らかなので、その後。
彼女らの存在意義、行成を好きにならなければならないという呪い、そう呪いだ、その枷を外れる者が少しくらい現われてもいいのではないだろうか。
あ、あと肌色と純白は増やさない方向で頼む。


2014/06/08 19:24 | Comments(0) | 買ったもの
PHP5.6.0 デストラクタだけカレントディレクトリが違う
<?php
	class HOGE{
		public function __construct(){
			var_dump(getcwd()); // C:\path\to\DocumentRoot\test
		}
		public function fuga(){
			var_dump(getcwd()); // C:\path\to\DocumentRoot\test
		}
		public function __destruct(){
			var_dump(getcwd()); // C:\xampp
		}
	}
	
	$hoge = new HOGE();
	$hoge->fuga();

PHPのシャットダウン中にデストラクタが呼ばれた場合、カレントディレクトリがサーバのルートに変わってしまいます。
chdir()等でカレントディレクトリを変更していた場合にも元に戻ってしまいます。

まあデストラクタの問題というよりはシャットダウン処理の仕様で、register_shutdown_function()でも同じ現象が発生します。

<?php
	register_shutdown_function(function(){
		var_dump(getcwd()); // C:\xampp
	});

ここまでであれば、相当わかりにくいけどどうにか納得できないこともない。
そういう仕様ならそれに合わせるしかあるまい。
<?php
	class HOGE{
		public function __construct(){
			var_dump(getcwd()); // C:\path\to\DocumentRoot\test
		}
		public function fuga(){
			var_dump(getcwd()); // C:\path\to\DocumentRoot\test
		}
		public function __destruct(){
			var_dump(getcwd()); // C:\path\to\DocumentRoot\test
		}
	}
	
	$hoge = new HOGE();
	$hoge->fuga();
	$hoge = 1;

なんてこった。
これはあかんで。
こちらはスクリプト中でデストラクタが呼ばれるため、カレントディレクトリが継続しています。

回避手段としては、デストラクタでディレクトリ/ファイルを扱わないというのもありますが、仕様上難しいこともあるでしょう。
実用的には、
・定数か何かでパス定義しといて常にフルパスで扱う
で問題ないでしょう。

なおディレクトリ名がC:\になっているのはXAMPPを使っているからで、Linux環境でも再現します。
getcwd()が/とかになる。


2014/06/06 20:10 | Comments(0) | PHP
PHP5.6.0 「第14回オフラインリアルタイムどう書くの参考問題」をPHPで解く
http://qiita.com/Nabetani/items/66806c9dc14a96f2fd42
http://nabetani.sakura.ne.jp/hena/ord14crosscircle/
円周上のCrossing

正直さっぱりわからなかったので諦めて他人の解答を見たのだが、余計わからなかった。
とりあえず1文字追加するごとに増える本数を数え上げるという形式で実装してみたところ、後半の問題が時間がかかりすぎて終わらないという有様に。
どうすればいいんだろう。
<?php
	class CROSSCIRCLE{
		/**
		* 円周上のCrossing
		* @param String 「aabbca1bcb」みたいな文字列
		* @return int 「14」みたいな数値
		*/
		public function get($input){
			// 初期値
			$count = 0;
			
			// 頭からくるくる
			for($i=0; $i<strlen($input)-1; $i++){
				$pos = $i+2;
				// 先に同じ文字が見つかれば
				while(($pos = strpos($input, $input[$i], $pos)) !== false){
					// 該当の文字で左右に区切る
					$c1 = count_chars(substr($input, $i+1, $pos-$i-1), 1);
					$c2 = count_chars(substr_replace($input, '', $i, $pos-$i+1), 1);
					// 左右に同じ文字があれば、文字数の積が交点の数
					foreach($c1 as $key=>$val){
						if(isset($c2[$key])){
							$count += $val*$c2[$key];
						}
					}
					$pos++;
				}
			}
			// 半分
			return $count/2;
		}
	}
	
	// 以下はテスト
	$test = [
		['aabbca1bcb', '14'],
		['111ZZZ', '0'],
		['v', '0'],
		['ww', '0'],
		['xxx', '0'],
		['yyyy', '1'],
		['zzzzz', '5'],
		['abcdef', '0'],
		['abcaef', '0'],
		['abbaee', '0'],
		['abcacb', '2'],
		['abcabc', '3'],
		['abcdabcd', '6'],
		['abcadeabcade', '23'],
		['abcdeedcba', '0'],
		['abcdeaedcba', '8'],
		['abcdeaedcbad', '16'],
		['QQQQXXXX', '2'],
		['QwQQmQXmXXwX', '14'],
		['111222333', '0'],
		['aaAAaA', '4'],
		['121232313', '12'],
		['1ab1b', '1'],
		['abcdefbadcfe', '12'],
		['abxcdefbadcfex', '14'],
		['dtnwtkt', '0'],
		['mvubvpp', '0'],
		['moggscd', '0'],
		['kzkjzpkw', '2'],
		['fbifybre', '1'],
		['rrrfjryki', '1'],
		['wrbbdwsdwtx', '2'],
		['vvucugvxbvgx', '9'],
		['ojkjzyasjwbfjj', '5'],
		['ggffyuxnkyypifff', '5'],
		['vcgtcqlwrepwvkkogl', '4'],
		['xeqtmmgppwcjpcisogxbs', '4'],
		['lukltpeucrqfvcupnpxwmoj', '6'],
		['zpzswlkkoqwwndwpfdpkhtzgtn', '31'],
		['bkfeflagfvluelududqjcvfyvytfw', '45'],
		['rvqbhfmcjjqlpqzulzerxgyowiwrfkmhw', '26'],
		['qyxvpdtoeexbqsethwjwmqszcxxjnsdoeaet', '144'],
		['rjmsgmswhcolmpbhmpncziymydyalrcnevsrespj', '133'],
		['oxetnyjzjbysnwktfwzndlejfndsqeetsnjvsicyjehd', '395'],
		['wzvddnddzogywcqxbyvagbzmsmtcmrrlbnebmvhaemjouaqim', '219'],
		['karhphxcxqgsyorhusbumbqzocuzvnwzwcpxgsksrviihxrgsrhji', '461'],
		['oxgbononhqdxzmkysgijwvxljpaazmgkurkpffeuwywwuyxhyfkicgyzyc', '441'],
		['sdgsrddwsrwqthhdvhrjhgtxwgurgyiygtktgtughtogzaqmcafkljgpniddsvb', '1077'],
		['qemhecchkgzhxmdcsltwhpoyhkapckkkzosmklcvzkiiucrvzzznmhjfcdumuflavxik', '1711'],
		['ffqmsirwpxrzfkbvmmfeptkbhnrvfcywthkwkbycmayhhkgvuyecbwwofwthlmzruphrcujwhr', '2440'],
	];

	$crosscircle = new CROSSCIRCLE();
	foreach($test as $key=>$data){
		$answer = $crosscircle->get($data[0]);
		if($answer !== (int)$data[1]){
			print('えらー');
		}
	}
普通に数えた。

まず1文字目の'a'に注目。
次に出てくる'a'を探すと、2文字目の'a'は間に線を引けないのでパス。
次の'a'は6文字目なので、そこで文字列を分解して'abbc'と'1bcb'を得る。
分解した文字のうち、'a'と'1'は片方にしかないので線を引けない。
'c'は左右に1つずつなので交点数は1*1=1。
'b'は左右に2つずつなので交点数は2*2=4。
次の'a'は存在しない、これで1文字目の'a'については終了。

次に1文字目の'a'に注目。
とまあ繰り返していって全部の合計を出した。
実行時間は0.1秒以下になった。はやい。

なお、最後の$pos++をwhile条件に突っ込もうとすると何故かWarningが発生します。


2014/06/02 23:38 | Comments(0) | PHP

<<前のページ | HOME | 次のページ>>
忍者ブログ[PR]