はてなキーワード: Stringとは
http://okajima.air-nifty.com/b/2010/01/post-abc6.html
迷路の最短経路を求める問題が出たので解いてみた
幅優先探索を使えばいいのがわかっていたのですんなりかけたのだが、無限ループになる個所があったので動くようになるまで時間がかかった
using System; using System.Collections.Generic; using System.Text; using System.Linq; namespace MazeFind { class Point { public int x; public int y; public Point before; public Point(int x, int y,Point before) { this.x = x; this.y = y; this.before = before; } } class Program { static void Main(string[] args) { const char BreakChar = 'B'; const char GoalChar = 'G'; const char WallChar = '*'; const char BeforeChar = '.'; StringBuilder[] maze = new StringBuilder[]{ new StringBuilder("**************************"), new StringBuilder("*S* * *"), new StringBuilder("* * * * ************* *"), new StringBuilder("* * * ************ *"), new StringBuilder("* * *"), new StringBuilder("************** ***********"), new StringBuilder("* *"), new StringBuilder("** ***********************"), new StringBuilder("* * G *"), new StringBuilder("* * *********** * *"), new StringBuilder("* * ******* * *"), new StringBuilder("* * *"), new StringBuilder("**************************"), }; Point start = new Point(1, 1,null); //最短経路を探索する Queue<Point> queque = new Queue<Point>(); queque.Enqueue(start); while (queque.Count > 0) { Point now = queque.Dequeue(); if (maze[now.y][now.x] == BreakChar) Console.WriteLine("break"); if (maze[now.y][now.x] == WallChar || maze[now.y][now.x] == BeforeChar) continue; else if (maze[now.y][now.x] == GoalChar) { Point p = now.before; while (p != null) { maze[p.y][p.x] = '@'; p = p.before; } break; } if (maze[now.y - 1][now.x] != '#') { queque.Enqueue(new Point(now.x, now.y - 1, now)); maze[now.y][now.x] = '.'; } if (maze[now.y][now.x + 1] != '#') { queque.Enqueue(new Point(now.x + 1, now.y, now)); maze[now.y][now.x] = '.'; } if (maze[now.y + 1][now.x] != '#') { queque.Enqueue(new Point(now.x, now.y + 1, now)); maze[now.y][now.x] = '.'; } if (maze[now.y][now.x - 1] != '#') { queque.Enqueue(new Point(now.x - 1, now.y, now)); maze[now.y][now.x] = '.'; } } //結果を出力する foreach (StringBuilder s in maze) Console.WriteLine(s.ToString().Replace(BeforeChar,' ')); Console.ReadLine(); } } } <||
最近は、24インチ 30インチディスプレイなんて安いんだから、横80ではなく横120ぐらいは平気で使える。
classname::enumname という毎回指定でも エディタがインテリジェントに保管してくれるから問題ない。
基本的に 外部ツールがチェックしてくれるんだから
enum{
{
};
で問題ないと思われ
言い方を変えれば、class内部以外でenumを定義することなんて最近はあるのか?グローバルなenumなんて余り無いと思うが・・・
クラス内部では、省略できるし、外部から、クラス内部の値を呼ぶときは、どのクラスのこのenumって外部だよって意味で毎回書いたほうが安全だろ?
using namespace std
ですら、書かないほうが安全 毎回std::って書かないと、うっかり、stringクラスを定義する人がいないとは限らんからね・・・
一斉に変更したい? エディタに正規表現で置換すればよろしい・・・
原則、外部のツールで解決できる問題は、外部のツールで解決すればいい。
言語仕様を拡張されると、初心者に、その理屈を説明するという問題が出てきて、そういうのは初心者には無理。
他方、ツールを使えない初心者でも、毎回コピペや手で置換は出来る。
オブジェクトのシリアライズツールであるプロトコルバッファについて書きます。
Protocol Buffers 本家
http://code.google.com/apis/protocolbuffers/
XMLはもう不要!? Google製シリアライズツール「Protocol Buffer」
http://journal.mycom.co.jp/articles/2008/07/18/protocolbuffer/index.html
Protocol Buffers (Protocol Buffers の内部解説記事。とても参考になります)
http://dodgson.org/omo/t/?date=20080712
プロトコルバッファは異種言語間でオブジェクトのやりとりをするための規格です。
独自の言語によりオブジェクトのインターフェースを規定することで、多言語対応を行っています。
例えばこんな感じ。
package tutorial; message Person { required string name = 1; required int32 id = 2; // Unique ID number for this person. optional string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { required string number = 1; optional PhoneType type = 2 [default = HOME]; } repeated PhoneNumber phone = 4; } // Our address book file is just one of these. message AddressBook { repeated Person person = 1; }
以上のようなprotoファイルから各言語のソースコード、または何らかのデータ操作ライブラリを使いオブジェクトの処理を行います。
googleによってC++, Java, Python用のライブラリが作成されましたが、他の言語に対応したサードパーティー製のライブラリがいくらでもあるので、実質的にほぼすべての言語で使えると言っても過言ではありません。
数字が多きければ大きいほど、長いバイト長で保存されます。ただし、負数の場合は符号ビットが立つ関係で、ほとんど常に変換後のバイト数が最長バイト数(10)になってしまいます。フィールドの型をsint32, sint64で宣言しると、各数値にzig-zags変換が行われるため、負数であってもその値の絶対値で使用バイト数が決まるようになります。
バイナリに保存されるデータは各メッセージのID/型/値のみです。なので、同じ定義の二つのメッセージ型は、プロトコルバッファ上では全く同じように扱うことが出来ます。例えば、片方からシリアライズしたデータを、もう片方の型でデシリアライズすることが可能です。
またオブジェクトを連続でシリアライズ/デシリアライズすることもできます。
すでに存在する継承関係のあるクラスを、Protocol Buffersでシリアライズ/デシリアライズしたい場合は次のようにします。
(ソースコード中になぜか日本語が書けないので、コメントはすべて英語になっています)
message PbBase { require int32 id = 1; require int32 value = 2; require Derived derived = 10; // - Point !!! } message PbDerived { require string string_value = 1; }
継承元のメッセージの定義に、継承先のメッセージを持たせます。Baseを継承するクラスをシリアライズ/デシリアライズしたい場合は、PbBaseメッセージを中心に処理を行うことで、比較的簡単に処理を実装することが出来ます。
例えばこんな感じ
Base *Base_DeserializeFrom(PbBase &amp;pbobj) { // Arrange the classes which inherits from Base. if (pbobj.has_derived()) { return new Derived(pbobj); } else ... } class Base { ... virtual void Base::SerializeTo(PbBase &amp;pbobj) { // Set the fields of 'pbobj', } ... }; class Derived { ... virtual void Base::SerializeTo(PbBase &amp;pbobj) { PbDerived *derived = pbobj.mutable_derived(); Base::SerializeTo(pbobj); // Set the fields of 'derived', ... } ... };
protoファイルを以下のように書くと、メッセージの扱いが非常に難しくなります。
message PbBase { require int32 id = 1; require int32 value = 2; } message PbDerived { required PbBase base = 1; // - Here is the point !!! require string string_value = 2; }
Rコンソールに一行ずつコマンドを入力してもいいけど、実際に使うにはテキストファイルにコマンドを書いて(ソースコード)一気に実行させる方が楽。
source('hogehoge.R')
hogehoge.Rというのがソースコードを書いたファイル(ソースファイル)の名前。
CRANという、CPANのパクリがある。膨大な数のライブラリがあるので、好きなものをインストールするには、
install.packages('hoge',dependencies=TRUE)
とするのが楽。
> あ<-1 > あ [1] 1
a<-1 b=2 1->a
どれでもいい。但し推奨されてるのは一番上。Rの人は「束縛」という言葉を使いたがる傾向があるけど、どっちでもいいと思う。
余談だけど、関数の引数の中で代入できる、しかもその値をそのあとの引数で使える。これ実は便利。
> sum(a<-1,a) [1] 2
> a [1] 1 > str(a) num 1 > summary(a) Min. 1st Qu. Median Mean 3rd Qu. Max. 1 1 1 1 1 1
最後のsummaryはRっぽい。strっていうのはstringではなくstructの略(だと思ってる)。Rの変数はいくらでも複雑な構造になり得るけど、そのときにぱっと見がわかるように構造を出力してくれる。
Rの基本はベクトル。
ベクトルの作り方はいくらでもあるけど、例示するのが早いでしょう。
> x<-1:3 > y<-c(TRUE, FALSE, TRUE) > z<-c("a","b","c") > x [1] 1 2 3 > y [1] TRUE FALSE TRUE > z [1] "a" "b" "c"
他にもいっぱいあるし、関数の返値がベクトルってこともよくある。
> runif(3) [1] 0.2200965 0.6391403 0.1089252
一様乱数を三個作った。
> x<-letters[1:5] > x [1] "a" "b" "c" "d" "e" > x[2] [1] "b" > x[4:5] [1] "d" "e" > x[c(1,3,5)] [1] "a" "c" "e"
こんな感じで、[]の中に添え字でアクセス。1-indexなので注意。2,3番目の例では添え字にもベクトルを使って、複数の要素に一気にアクセスしてる。
> x[3]<-"z" > x [1] "a" "b" "z" "d" "e"
でOK。
要望があれば続くかも。
http://anond.hatelabo.jp/20100119023114
しょぼい煽りだなあ。
煽りに見えるのかなあ。
そりゃそうですが。
よくできたアプリを公開している人は、定義からして優れたプログラマなわけですが、何も公開しない人は、優れたプログラマかどうかはわからない。
優れたプログラマがアプリを公開しているとは限らないですが、公開しない人が優れたプログラマであるとは限らない。
もちろん「優れたプログラマであるとは限らない」だけで、優れたプログラマではないと断定はできないですが、これだけの長期にわたってこれだけ大量のエントリを投下している割に、具体的な技術の話がさっぱりないのはかなり異様に見えます。
昔はコードを少し載せてた。
ちょっと見てみた。
http://d.hatena.ne.jp/JavaBlack/archive/200503
2005年の分をタイトルだけさらってみたけど、コードが載ってるのは上記のStringの結合ネタぐらいのような……もちろんこういう記事はJavaプログラマにとっては(中級異常のプログラマには常識の範疇とはいえ)かなり役に立つ記事だと思うんですよ。でも、その後そういう記事は減少の一方じゃないですか?
このリストはJavaやる人なら必須でしょ。このリストを作ってくれてるだけでブログレベルでは十分だと思う。
Java&オブジェクト指向参考書リスト(2007年版)http://d.hatena.ne.jp/JavaBlack/20070522/p1
普通のブログ記事として、この記事だけを見たら、悪くないエントリだと思う。
でも、逆に言うとどれも標準的な必読書。内容に関する言及もないので、それこそ本をまったく読まなくても、ネットで評判を調べるだけでこのリストは作れそうだ(JavaBlack氏がこれらの本を読んでないと言っているわけじゃない。邦訳ぐらいは読んでると思う)。
でもさ、普段あれだけ上から目線の偉そうなエントリを連投している割には、ご本人の技術力は、さっぱり具体的には見えてこない。
ブコメだと、(今回の地震の話はさておき)そこそこ好意的なコメントが付くようだけど、そのへんみんなどう思ってるのかな、と思ったわけですよ。
全能感を維持するために「なにもしない」人達
http://d.hatena.ne.jp/p_shirokuma/20100119/p1
JavaBlack氏は、自らの全能感を維持するために、コードを書いたり公開したりしないのかな、という気もちょっとする。
実力を晒さない限りは、馬鹿にされることもないからね。
ええと、ご本人がこれを見ることがあるとしたら、
と言いたいです。JavaBlack氏がまだ求職中なのかどうか知らないけど、もし私がうちの会社の人事権を持っていたとしても、悪いがこの人は採らない。
34分
現役のときに比べて腕が鈍ってるなあ
ソースは汚いよ
同じところを二回訪れないことに注意して、次の状態をキューに入れていけばいいだけ
隣は距離1なのでただのFIFOでいい
重み付きのグラフならpriority queueを使う
dequeなんちゃらの前までが入力で、while の中が重要なコード
答えはSとGも塗り潰しちゃったのを出力してる
サンプルの入力で最短距離であることを確認してる
#include <map> #include <string> #include <iostream> #include <vector> #include <iterator> #include <deque> #include <set> using namespace std; typedef pair<int, int> P; int dir_x[] = {0,1, -1, 0}; int dir_y[] = {1, 0, 0, -1}; int main() { string line; vector<string> input; while (getline(cin, line)) { input.push_back(line); } const int X = input.size(); const int Y = input.begin()->size(); vector<P> start; P goal; for (int i = 0; i < X; i++) { for (int j = 0; j < Y; j++) { if (input[i][j] == 'S') { start.push_back(P(i, j)); } else if (input[i][j] == 'G') { goal = P(i, j); } } } deque<vector<P> > Q; set<P> visited; Q.push_back(start); while (!Q.empty()) { vector<P> p = Q.front(); Q.pop_front(); if (visited.find(p.back()) != visited.end()) { continue; } visited.insert(p.back()); if (p.back() == goal) { for (int i = 0; i < p.size(); i++) { input[p[i].first][p[i].second] = '$'; } copy(input.begin(), input.end(), ostream_iterator<string>(cout, "\n")); break; } for (int i = 0; i < 4; i++) { P next = P(p.back().first + dir_x[i], p.back().second + dir_y[i]); if (input[next.first][next.second] == '*') { continue; } vector<P> new_state(p.begin(), p.end()); new_state.push_back(next); Q.push_back(new_state); } } return 0; }
これで40分。
タイムアタックってことでアルゴリズムは全幅探索で書き上げました。
エラーチェック皆無。
A*ならもう5分ほど延びるかな?
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; namespace Maze { class Program { // 探索用地図 static int[,] maze; // 始点終点 static Position Start = new Position(0, 0), Goal = new Position(0, 0); static void Main(string[] args) { //////////////////////////// まずは各行のリストとして読み込み string[] inMaze; using (var fp = new FileStream(args[0], FileMode.Open, FileAccess.Read)) using (var iStream = new StreamReader(fp)) inMaze = iStream.ReadToEnd().Split('\n'); // 迷路幅 int height = inMaze.Length; // 迷路高さ int width = inMaze[0].Length; /////////////////////////// 読み込んだ迷路を作業用地図に展開 maze = new int[width, height]; for (int y = 0; y < height; ++y) { string line = inMaze[y]; for (int x = 0; x < line.Length; ++x) { maze[x, y] = line[x] == '*' ? -1 : 0; if (line[x] == 'S') Start = new Position(x, y); if (line[x] == 'G') Goal = new Position(x, y); } } // 探索実行 int dist = Search(maze, Start); // 探索結果から最短経路を再現 Position backTracer = Goal; while (dist>1){ --dist; backTracer = backTracer.Nearbys.First(pos => maze[pos.X,pos.Y] == dist); maze[backTracer.X, backTracer.Y] = -2; } //////////////////// 最短経路こみのアスキー地図に変換 char[,] outMaze = new char[width, height]; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { outMaze[x, y] = maze[x, y] == -2 ? '$' : maze[x, y] == -1 ? '*' : ' '; } } outMaze[Start.X, Start.Y] = 'S'; outMaze[Goal.X, Goal.Y] = 'G'; ////////////////////// 結果は標準出力に。 for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) Console.Write(outMaze[x, y]); Console.WriteLine(); } Console.ReadLine(); } /// <summary> /// 探索する。SG間の道のりを返す(道のり=SGが隣接しているなら1) /// </summary> private static int Search(int[,] maze, Position Start) { List<Position> FrontLine = new List<Position>(); FrontLine.Add(Start); int dist = 1; for (; ; ) { List<Position> NextFrontLine = new List<Position>(); foreach (var pos in FrontLine) { foreach (var nextPos in pos.Nearbys) { if (nextPos == Goal) return dist; if (maze[nextPos.X, nextPos.Y] == 0) { maze[nextPos.X, nextPos.Y] = dist; NextFrontLine.Add(nextPos); } } } FrontLine = NextFrontLine; ++dist; } } } struct Position { public readonly int X, Y; public Position(int x, int y) { X = x; Y = y; } public IEnumerable<Position> Nearbys { get { return new[]{ new Position(X-1,Y), new Position(X,Y-1), new Position(X+1,Y), new Position(X,Y+1), }; } } public static bool operator==(Position p1, Position p2){ return p1.X == p2.X && p1.Y == p2.Y; } public static bool operator!=(Position p1, Position p2){ return p1.X != p2.X || p1.Y != p2.Y; } } }
10/18 改訂
なお、取得した画像の著作権はグーグル他各社が保持しています。
ご利用は計画的に私的範囲でどうぞご利用ください。
#!/usr/bin/perl use strict; use warnings; use Getopt::Long; use LWP::UserAgent; use GD; my $cmdline = join(" ", $0, @ARGV); my $usage = "usage: $0 -sx=116423 -sy=51603 -ex=116426 -ey=51605 -dx=4 -dy=3 -z=17 -size=300 -get=30 -dir=cache -output=output.jpg -nodebug"; my ($sx, $sy) = (0, 0); my ($ex, $ey) = (0, 0); my ($dx, $dy) = (4, 3); my $z = 17; my $size = 300; my $get = 30; my $dir = "cache"; my $output = "output.jpg"; my $debug = 0; GetOptions("sx=i" => \$sx, "sy=i" => \$sy, "ex=i" => \$ex, "ey=i" => \$ey, "dx=i" => \$dx, "dy=i" => \$dy, "z=i" => \$z, "size=i" => \$size, "get=i" => $get, "dir=s" => \$dir, "output=s" => \$output, "debug!" => \$debug) or die "$usage\nDied"; if ($ex == 0) { $ex = $sx + $dx; } else { $ex++; $dx = $ex - $sx; } if ($ey == 0) { $ey = $sy + $dy; } else { $ey++; $dy = $ey - $sy; } $sx>0 and $dx>0 and $sy>0 and $dy>0 and $z>0 and $dir and $output or die "$usage\nBad arguments"; $dx*$dy > $size and die "Getting too large."; $debug and print "debug: mkdir $dir\n"; mkdir $dir; -d $dir or die "can't make dir $dir: $!"; my $base = sprintf("http://khm%d.google.co.jp/kh/v=46&z=%d", int(rand(4)), $z); my $ua = LWP::UserAgent->new; printf "now get %d images...\n", $dx*$dy; for (my $x=$sx; $x < $ex; $x++) { for (my $y=$sy; $y < $ey; $y++) { my $file = sprintf("%s/%02dz%06dx%06d.jpg", $dir, $z, $x, $y); $debug and print "debug: check of $file\n"; -s $file and next; --$get < 0 and last; my $req = HTTP::Request->new(GET=>+"$base&x=$x&y=$y"); $debug and print "debug: fetch from ".$req->uri."\n"; my $res = $ua->request($req); unless ($res->is_success) { print "fail fetch from $file: ", $res->status_line, "\n"; next; } if (open(my $fh, ">", $file)) { $debug and print "debug: write of $file\n"; binmode $fh; print $fh $res->content; close $fh; } else { print "fail open in $file: $!\n"; } } } $get < 0 and print "reach the getting limit, skip after all.\n"; printf "creating %dX%d image...\n", 256*$dx, 256*$dy; my $image = new GD::Image(256*$dx, 256*$dy); for (my $x=$sx; $x < $ex; $x++) { for (my $y=$sy; $y < $ey; $y++) { my $file = sprintf("%s/%02dz%06dx%06d.jpg", $dir, $z, $x, $y); $debug and print "debug: check of $file\n"; -s $file or next; $debug and print "debug: read of $file\n"; my $part = GD::Image->newFromJpeg($file); $debug and print "debug: image copy\n"; $image->copy($part, 256*($x-$sx), 256*($y-$sy), 0, 0, 256, 256); } } #$image->string(gdSmallFont, 0, 0, $cmdline, $image->colorAllocate(255, 255, 255)); open(my $fh, ">", $output) or die "fail open $output: $!"; $debug and print "debug: write of $output\n"; binmode $fh; print $fh $image->jpeg(); close $fh;
例えば秋葉原とか
perl gmwall.pl -sx=116423 -sy=51603 -ex=116427 -ey=51606
駅だけとか
perl gmwall.pl -sx=465701 -sy=206420 -ex=465705 -ey=206423 -z=19
使う数値はfirebugなどで拾ってください。
class FizzBuzzProgram{ public static void main(String args[]){ for (int i = 0; i++ < 100; ) { System.out.println(new Number(i).checkMod3().checkMod5()); } } } interface Mod3Mod5Unchecked extends Mod5Unchecked { public Mod5Unchecked checkMod3(); } interface Mod5Unchecked { public Object checkMod5(); } class Number implements Mod3Mod5Unchecked{ private int no; public Number (int no) { this.no = no; } public Mod5Unchecked checkMod3() { return no % 3 == 0 ? new Fizz(no) : this; } public Object checkMod5() { return no % 5 == 0 ? new Buzz() : this; } public String toString() { return Integer.toString(no); } } class Fizz implements Mod5Unchecked{ private int no; public Fizz (int no) { this.no = no; } public Object checkMod5() { return no % 5 == 0 ? new FizzBuzz() : this; } public String toString() { return "Fizz"; } } class Buzz { public String toString() { return "Buzz"; } } class FizzBuzz { public String toString() { return "FizzBuzz"; } }
platinumで吐き出せるFMFを読み取るためクラスを置いておく。特に反省はしてない。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Data; namespace RPG { class MapFile { //FMFファイルのヘッダー struct FMFHeader { public string dwIdentifier; // ファイル識別子 'FMF_' public int dwSize; // ヘッダを除いたデータサイズ public int dwWidth; // マップの横幅 public int dwHeight; // マップの高さ public byte byChipWidth; // マップチップ1つの幅(pixel) public byte byChipHeight; // マップチップ1つの高さ(pixel) public byte byLayerCount; // レイヤーの数 public byte byBitCount; // レイヤデータのビットカウント } private FileStream fs; private BinaryReader br; private FMFHeader _head; private byte[] _data8 = null; private short[] _data16 = null; public int width { get { return _head.dwWidth; } } public int height { get { return _head.dwHeight; } } public int chip_width { get { return _head.byChipWidth; } } public int chip_height { get { return _head.byChipHeight; } } //マップファイルを読み込む。 //エラーが起きた場合は例外を投げます public void Load(String fname) { try { fs = new FileStream(fname, FileMode.Open); br = new BinaryReader(fs); //識別子を確認する _head.dwIdentifier = new String(br.ReadChars(4)); if (_head.dwIdentifier != "FMF_") { throw new Exception("ファイルが壊れています"); } //ヘッダーの残りの情報を読み込む _head.dwSize = br.ReadInt32(); _head.dwWidth = br.ReadInt32(); _head.dwHeight = br.ReadInt32(); _head.byChipWidth = br.ReadByte(); _head.byChipHeight = br.ReadByte(); _head.byLayerCount = br.ReadByte(); _head.byBitCount = br.ReadByte(); switch (_head.byBitCount) { case 8: //8bit layer _data8 = br.ReadBytes(_head.dwSize); break; case 16: //16it layer int count = _head.dwSize / 2; _data16 = new short[count]; for(int i = 0; i < count; i++) _data16[i] = br.ReadInt16(); break; } } catch(Exception ex) { throw ex; } finally { br.Close(); } } //マップファイルを閉じます public void close() { //読み込んだデータを破棄する _data8 = null; _data16 = null; } //マップファイルからチップ番号を取得します public int getValue(int layer_index, int x, int y) { if (_data8 == null &amp;&amp; _data16 == null) return -1; if (layer_index >= _head.byLayerCount || x >= _head.dwWidth || y >= _head.dwHeight) return -1; int index = 0; int layer_offset = getLayerAddr(layer_index); switch (_head.byBitCount) { case 8: //8bit layer index = _data8[layer_offset + x + y * _head.dwWidth]; break; case 16: //16it layer index = _data16[layer_offset + x + y * _head.dwWidth]; break; } return index; } //該当レイヤーが存在する_dataのindexを返す private int getLayerAddr(int layer_index) { if (layer_index >= _head.byLayerCount || (_data8 == null &amp;&amp; _data16 == null)) return -1; return _head.dwWidth * _head.dwHeight * layer_index; } } }
#訂正
if ("0x0A" == "10") { print '(´ε` )チュッ'; }
チュッ。されちゃいます。
文字列であっても整数と解釈できる文字列の場合は勝手に型変換しやがる今世紀最大の愚行を犯してしまうってのは有名な話だよね。
文字列であっても整数と解釈できる文字列の場合は自動的に整数に型変換してくれる超便利機能があるってのは有名な話だよね。
だけどなんでコレが一致するかわけがわからんかった。
0x0Aは10進数で10になるので一致する。と、言いたいところなんですがそう単純な話じゃないんだ。
以下の例を目ん玉見開いて見て欲しい。
var_dump(0x0A); var_dump("0x0A"); var_dump((int)"0x0A"); var_dump((float)"0x0A"); var_dump(intval("0x0A")); 実行結果 int(10) string(4) "0x0A" int(0) float(0) int(0)
つまり文字列の"0x0A"ってやつはどう考えても0と解釈されるはずなんだ。だから上記if文が本来一致するはずがいない。
でも実際は何故か10と解釈されて一致してしまう。
そう、つまり演算子で比較した場合、やらんでもいいのにわざわざ16進表記かどうかまでチェックして余計なお世話的うんこ変換しやがるということになる。
そう、つまり演算子で比較した場合は、16進表記かどうかまでチェックして10進数に変換してくれているということになる。
明示的に書くならこんな感じだ。
if (intval("0x0A",16) == "10") { print '(´ε` )チュッ'; }
クソが。
なるほどねー。
ただでさえ文字列同士の比較なのにintに変換されるだけでもミソ糞うぜぇのに、わざわざ16進数の場合は10進数に変換してくれる超糞尿仕様。
文字列同士の比較であってもintに自動変換してくれるだけでも素晴らしいのに、それに加えて16進数の場合は10進数に変換してくれる超便利仕様。
ってこたぁ、8進数表記の場合も糞糞マジ死ぬほど余計なお世話するんだろうなぁと思ってしぶしぶ試してみた。
ということは8進数表記の場合もこの素晴らしい自動変換しれくるのかなと思って試してみた。
if ("0x0A" == "012") { print '(´ε` )チュッ'; } else { print '\(^o^)/'; } 実行結果 \(^o^)/
おー、さすがPHP!、やっぱ8進数の場合は10進数と似てるから8進数と見なすよりも10進数と見なしたほうが効率いいですもんね。いやーわかってるなー。ますますPHPが好きになりました。I Love PHP. We Love P☆H☆P!
はは、はははっ、ははははっ。やるならやる!やらないならやらない!どっちかに統一せーやこのプリンシパル校長ヘッドハンティンピープルぺーぺーぽりんき味噌マッチョ変態改造エアガン陵辱-2くらいのスカンク殺ろうがぁああああああ★ああああああああああああああああああああああああああああああああああああああfじょ★えいjfsきじぇいつつしまじいのそるいつのだ★ひろけがきちもするけけけそあいんぼろうれあああぁあああああaaaaaa
セキュリティ目的ではない。ハッシュテーブルで使うような奴でキャッシュで使いたい。
手軽なほうが良い。軽いほうが良い。推測可能でよい。数十バイトくらいの文字列にしたい。
md5が一番汎用っぽいけど、無駄に重い気がする。crc32は軽そうだしそれなりに汎用っぽいけど、ハッシュ長が短いのがめんどい。
調べた→ http://anond.hatelabo.jp/20090327015620
ベンチ用スクリプト
#!/usr/local/bin/python from sys import argv, stderr from time import time from string import ascii_letters, join from random import choice from hashlib import md5 from binascii import crc32 from itertools import izip time_fmt = '%10s: %5d ms' shift = int(argv[1]) if len(argv)>1 and argv[1].isdigit() else 2 length = 0x100 << shift cycle = 0x10000 >> shift print >> stderr, 'string length: 0x%x, cycle: 0x%x' % (length, cycle) data = tuple(''.join(choice(ascii_letters) for i in xrange(length)) for j in xrange(cycle)) start = time() md5hex = tuple(md5(s).hexdigest() for s in data) print >> stderr, time_fmt % ('md5hex', (time() - start) * 1000) start = time() crc32x4 = tuple(''.join('%08x' % abs(crc32(s[i::4])) for i in (0, 1, 2, 3)) for s in data) print >> stderr, time_fmt % ('crc32x4', (time() - start) * 1000) start = time() startend = tuple(s[:16]+s[-16:] for s in data) print >> stderr, time_fmt % ('headtail', (time() - start) * 1000) start = time() skip = tuple(s[::(len(s)/32+1)] for s in data) print >> stderr, time_fmt % ('skipover', (time() - start) * 1000) for s in izip(data, md5hex, crc32x4, startend, skip): print join(s)
実行結果
% python hashbench.py 0 > hash0.txt string length: 0x100, cycle: 0x10000 md5hex: 199 ms crc32x4: 1081 ms headtail: 30 ms skipover: 41 ms % python hashbench.py 2 > hash1.txt string length: 0x400, cycle: 0x4000 md5hex: 83 ms crc32x4: 363 ms headtail: 10 ms skipover: 20 ms % python hashbench.py 4 > hash2.txt string length: 0x1000, cycle: 0x1000 md5hex: 52 ms crc32x4: 170 ms headtail: 2 ms skipover: 5 ms
↓
<style type="text/css">dt{float:left;clear:left;width:10em;}</style>
<meta content="charset=Shift_JIS"/>
<script type="text/javascript"></p> <p>window.onload = init;</p> <p>var url = [</p> <p> "<a href="http://www.senkyo.metro.tokyo.jp/h19sangiin/san_kekka/h19san_hkai.html">http://www.senkyo.metro.tokyo.jp/h19sangiin/san_kekka/h19san_hkai.html</a>",</p> <p> "<a href="http://www.senkyo.metro.tokyo.jp/h17shugiin/sokuhou/7kaijyo_s.htm">http://www.senkyo.metro.tokyo.jp/h17shugiin/sokuhou/7kaijyo_s.htm</a>",</p> <p> "<a href="http://www.senkyo.metro.tokyo.jp/h17togisen/sokuhou/2kaijyo_s.htm">http://www.senkyo.metro.tokyo.jp/h17togisen/sokuhou/2kaijyo_s.htm</a>",</p> <p> "<a href="http://www.senkyo.metro.tokyo.jp/data/h16san_hkai.html">http://www.senkyo.metro.tokyo.jp/data/h16san_hkai.html</a>",</p> <p> "<a href="http://www.senkyo.metro.tokyo.jp/data/h15shu_hkai.html">http://www.senkyo.metro.tokyo.jp/data/h15shu_hkai.html</a>",</p> <p> "<a href="http://www.senkyo.metro.tokyo.jp/data/data01_01_03.html">http://www.senkyo.metro.tokyo.jp/data/data01_01_03.html</a>",</p> <p> "<a href="http://www.senkyo.metro.tokyo.jp/data/data01_02_05.html">http://www.senkyo.metro.tokyo.jp/data/data01_02_05.html</a>",</p> <p> "<a href="http://www.senkyo.metro.tokyo.jp/data/data03_04.html">http://www.senkyo.metro.tokyo.jp/data/data03_04.html</a>",</p> <p> "<a href="http://www.senkyo.metro.tokyo.jp/data/data01_05_05.html">http://www.senkyo.metro.tokyo.jp/data/data01_05_05.html</a>"</p> <p>];</p> <p>var base = "<a href="http://www.senkyo.metro.tokyo.jp/data/tokuhyo_23ku/">http://www.senkyo.metro.tokyo.jp/data/tokuhyo_23ku/</a>";</p> <p>var file = ["chiyoda","chuou","minato","shinjyuku","bunkyo",</p> <p> "taitho","sumida","koutho","sinagawa","meguro",</p> <p> "ohta","setagaya","shibuya","nakaono","suginami",</p> <p> "toshima","kita","arakawa","itabashi","nerima",</p> <p> "adachi","katushika","edogawa"];</p> <p>for(var i=0; i<23; i++){</p> <p> url.push(base + file[i] + "\.html");</p> <p>}</p> <p>var id = [</p> <p> "2007 参院比", "2005 衆院比", "2005 都議会", "2004 参院比", "2003 衆院比",</p> <p> "2001 参院比", "2001 都議会", "2000 衆院比", "1998 参院比", "1997 都議会"</p> <p>];</p> <p>var ku = [</p> <p> "千代田","中央","港","新宿","文京",</p> <p> "台東","墨田","江東","品川","目黒",</p> <p> "大田","世田谷","渋谷","中野","杉並",</p> <p> "豊島","北","荒川","板橋","練馬",</p> <p> "足立","葛飾","江戸川"</p> <p>];</p> <p>var regexku = new RegExp("(" + ku.join("|") + ")区");</p> <p>var iframe = [];</p> <p>var data = {};</p> <p>var parse = [ function(){</p> <p> var d = iframe[0].contentWindow.document;</p> <p> var td = d.getElementsByTagName("td");</p> <p> for(var i=0, l=td.length; i<l; i++){</p> <p> if(regexku.test(td[i].firstChild.nodeValue)){</p> <p> for(var j=0, e=td[i]; j<10; j++){</p> <p> e = e.nextSibling;</p> <p> }</p> <p> data[RegExp.$1 + "0"] = e.firstChild.firstChild.nodeValue.replace(/\.\d+/,"");</p> <p> }</p> <p> }</p> <p> show();</p> <p>}, function(){</p> <p> var d = iframe[1].contentWindow.document;</p> <p> var nobr = d.getElementsByTagName("nobr");</p> <p> for(var i=0, l=nobr.length; i<l; i++){</p> <p> if(regexku.test(nobr[i].firstChild.nodeValue)){</p> <p> for(var j=0, e=nobr[i].parentNode; j<4; j++){</p> <p> e = e.nextSibling;</p> <p> }</p> <p> data[RegExp.$1 + "1"] = e.firstChild.nodeValue;</p> <p> }</p> <p> }</p> <p> show();</p> <p>}, function(){</p> <p> var d = iframe[2].contentWindow.document;</p> <p> var nobr = d.getElementsByTagName("nobr");</p> <p> for(var i=0, l=nobr.length; i<l; i++){</p> <p> if(regexku.test(nobr[i].firstChild.nodeValue) && nobr[i].parentNode.tagName == "SPAN"){</p> <p> for(var j=0, e=nobr[i]; j<6; j++){</p> <p> e = e.parentNode;</p> <p> }</p> <p> var e2 = e.nextSibling.nextSibling.firstChild.childNodes[2].firstChild;</p> <p> var k = 0;</p> <p> data[RegExp.$1 + "2"] = 0;</p> <p> while(e2){</p> <p> if(e2.firstChild.firstChild.nodeValue.indexOf("公明党") != -1){</p> <p> data[RegExp.$1 + "2"] += parseInt(e2.parentNode.nextSibling.childNodes[k+2].firstChild.nodeValue.replace(",",""), 10);</p> <p> }</p> <p> e2 = e2.nextSibling;</p> <p> k++;</p> <p> }</p> <p> data[RegExp.$1 + "2"] = int2str(data[RegExp.$1 + "2"]);</p> <p> }</p> <p> }</p> <p> show();</p> <p>}, function(){</p> <p> var d = iframe[3].contentWindow.document;</p> <p> var td = d.getElementsByTagName("td");</p> <p> for(var i=0, l=td.length; i<l; i++){</p> <p> if(regexku.test(td[i].firstChild.nodeValue)){</p> <p> for(var j=0, e=td[i]; j<19; j++){</p> <p> e = e.nextSibling;</p> <p> }</p> <p> data[RegExp.$1 + "3"] = e.firstChild.firstChild.nodeValue.replace(/\.\d+/,"");</p> <p> }</p> <p> }</p> <p> show();</p> <p>}, function(){</p> <p> var d = iframe[4].contentWindow.document;</p> <p> var td = d.getElementsByTagName("td");</p> <p> var regexku2 = /(大田|世田谷|練馬|足立|江戸川)/;</p> <p> for(var i=0, l=td.length; i<l; i++){</p> <p> if(regexku.test(td[i].firstChild.nodeValue)){</p> <p> data[RegExp.$1 + "4"] = td[i].nextSibling.nextSibling.firstChild.nodeValue.replace(/\.\d+/,"");</p> <p> continue;</p> <p> }</p> <p> if(regexku2.test(td[i].firstChild.nodeValue)){</p> <p> data[RegExp.$1 + "4"] = (data[RegExp.$1 + "4"] || 0) </p> <p> + parseInt(td[i].nextSibling.nextSibling.firstChild.nodeValue.replace(",","").replace(/\.\d+/,""));</p> <p> }</p> <p> }</p> <p> for(var j=0; j<5; j++){</p> <p> data[ku[[10,11,19,20,22][j]]+"4"] = int2str(data[ku[[10,11,19,20,22][j]]+"4"]);</p> <p> }</p> <p> show();</p> <p>}, function(){</p> <p> var d = iframe[5].contentWindow.document;</p> <p> var td = d.getElementsByTagName("td");</p> <p> for(var i=0, l=td.length; i<l; i++){</p> <p> if(regexku.test(td[i].firstChild.firstChild.nodeValue)){</p> <p> for(var j=0, e=td[i]; j<10; j++){</p> <p> e = e.nextSibling;</p> <p> }</p> <p> data[RegExp.$1 + "5"] = e.firstChild.firstChild.nodeValue.replace(/\.\d+/,"");</p> <p> }</p> <p> }</p> <p> show();</p> <p>}, function(){</p> <p> var d = iframe[6].contentWindow.document;</p> <p> var td = d.getElementsByTagName("td");</p> <p> for(var i=0, l=td.length; i<l; i++){</p> <p> if(regexku.test(td[i].firstChild.firstChild.nodeValue)){</p> <p> for(var j=0, e=td[i]; j<7; j++){</p> <p> e = e.nextSibling;</p> <p> }</p> <p> data[RegExp.$1 + "6"] = e.firstChild.firstChild.nodeValue.replace(/\.\d+/,"").replace("-","0");</p> <p> }</p> <p> }</p> <p> show();</p> <p>}, function(){</p> <p> var d = iframe[7].contentWindow.document;</p> <p> var td = d.getElementsByTagName("td");</p> <p> for(var i=0, l=td.length; i<l; i++){</p> <p> if(regexku.test(td[i].firstChild.firstChild.nodeValue)){</p> <p> for(var j=0, e=td[i]; j<9; j++){</p> <p> e = e.nextSibling;</p> <p> }</p> <p> data[RegExp.$1 + "7"] = e.firstChild.firstChild.nodeValue;</p> <p> }</p> <p> }</p> <p> show();</p> <p>}, function(){</p> <p> var d = iframe[8].contentWindow.document;</p> <p> var td = d.getElementsByTagName("td");</p> <p> for(var i=0, l=td.length; i<l; i++){</p> <p> if(regexku.test(td[i].firstChild.firstChild.nodeValue)){</p> <p> data[RegExp.$1 + "8"] = int2str(td[i].nextSibling.firstChild.firstChild.firstChild.nodeValue);</p> <p> }</p> <p> }</p> <p> show();</p> <p>}, function(n){ return function(){</p> <p> var d = iframe[n+9].contentWindow.document;</p> <p> var td = d.getElementsByTagName("td");</p> <p> data[ku[n]+"9"] = 0;</p> <p> for(var i=0, l=td.length; i<l; i++){</p> <p> if((((td[i].firstChild || 0).firstChild || 0).nodeValue || "").indexOf("公明") == 0){</p> <p> data[ku[n]+"9"] += parseInt(td[i].parentNode.lastChild.firstChild.firstChild.nodeValue.replace(",",""));</p> <p> }</p> <p> }</p> <p> data[ku[n]+"9"] = int2str(data[ku[n]+"9"]);</p> <p> show();</p> <p>}}];</p> <p>function init(){</p> <p> for(var i=0; i<23; i++){</p> <p> var dl = document.createElement("dl");</p> <p> dl.appendChild(document.createTextNode("\n【" + ku[i] + "区における公明票】\n"));</p> <p> for(var j=0; j<10; j++){</p> <p> var dt = document.createElement("dt");</p> <p> var dd = document.createElement("dd");</p> <p> dt.innerText = id[j];</p> <p> dl.appendChild(dt);</p> <p> dl.appendChild(dd);</p> <p> }</p> <p> document.body.firstChild.appendChild(dl);</p> <p> }</p> <p> for(var i=0; i<32; i++){</p> <p> var e = document.createElement("iframe");</p> <p> iframe[i] = e;</p> <p> e.style.display = "none";</p> <p> if(i<9) var f = parse[i];</p> <p> else var f = parse[9](i-9);</p> <p> e.attachEvent("onload", f);</p> <p> e.src = url[i];</p> <p> document.body.appendChild(e);</p> <p> }</p> <p>}</p> <p>function show(){</p> <p> for(var i=0; i<23; i++){</p> <p> var dl = document.body.firstChild.childNodes[i];</p> <p> for(var j=0; j<10; j++){</p> <p> var dt = dl.childNodes[j*2+1];</p> <p> dt.innerText = id[j] + " " + (data[ku[i]+j] || "");</p> <p> dt.nextSibling.innerText = bar(data[ku[i]+j], j);</p> <p> }</p> <p> }</p> <p>}</p> <p>function int2str(num){</p> <p> return new String(num).split("").reverse().join("").replace(/(\d{3})/g,"$1,").split("").reverse().join("");</p> <p>}</p> <p>function bar(str, flag){</p> <p> str = str || "";</p> <p> if(str == "" || str.length < 5) return "";</p> <p> var num = parseInt(str.match(/\d+/)) + 1;</p> <p> var arrow = (flag == 2 || flag == 6 || flag == 9) ? " ←" : "";</p> <p> var _bar = new Array(num).join("|") + arrow;</p> <p> return _bar;</p> <p>}</p> <p></script>
// ==UserScript== // @name anond // @namespace http://anond.hatelabo.jp/ // @include http://anond.hatelabo.jp/?page=* // ==/UserScript== function anond(doc) { $X(".//div[@class='section'][.//h3/a[2][starts-with(@href, 'http://anond.hatelabo.jp')]]", doc, Array).forEach(function(node){ node.style.display = "none"; }); $X(".//h3/a[1]", doc, Array).forEach(function(node){ var a = document.createElement("a"); a.name = node.pathname; a.href = "#" + node.pathname + "/footer"; a.innerHTML = "V"; node.parentNode.insertBefore(a, node); }); $X(".//p[@class = 'sectionfooter']/a[1]", doc, Array).forEach(function(node){ var a = document.createElement("a"); a.name = node.pathname + "/footer"; a.href = "#" + node.pathname; a.innerHTML = "^"; node.parentNode.insertBefore(a, node); node.parentNode.insertBefore(document.createTextNode(" | "), node); }); } anond(document); if (AutoPagerize.addDocumentFilter) AutoPagerize.addDocumentFilter(anond); // by http://lowreal.net/blog/2007/11/17/1 // $X(exp); // $X(exp, context); // $X(exp, type); // $X(exp, context, type); function $X (exp, context, type /* want type */) { if (typeof context == "function") { type = context; context = null; } if (!context) context = document; var exp = (context.ownerDocument || context).createExpression(exp, function (prefix) { var o = document.createNSResolver(context).lookupNamespaceURI(prefix); if (o) return o; return (document.contentType == "application/xhtml+xml") ? "http://www.w3.org/1999/xhtml" : ""; }); switch (type) { case String: return exp.evaluate( context, XPathResult.STRING_TYPE, null ).stringValue; case Number: return exp.evaluate( context, XPathResult.NUMBER_TYPE, null ).numberValue; case Boolean: return exp.evaluate( context, XPathResult.BOOLEAN_TYPE, null ).booleanValue; case Array: var result = exp.evaluate( context, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); var ret = []; for (var i = 0, len = result.snapshotLength; i < len; i++) { ret.push(result.snapshotItem(i)); } return ret; case undefined: var result = exp.evaluate(context, XPathResult.ANY_TYPE, null); switch (result.resultType) { case XPathResult.STRING_TYPE : return result.stringValue; case XPathResult.NUMBER_TYPE : return result.numberValue; case XPathResult.BOOLEAN_TYPE: return result.booleanValue; case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: { // not ensure the order. var ret = []; var i = null; while (i = result.iterateNext()) { ret.push(i); } return ret; } } return null; default: throw(TypeError("$X: specified type is not valid type.")); } }
修正:いい加減&が変換されるのを何とかしてほしい
解説:Hatena::Bookmark::24H(http://hatebu24h.ashitano.in/)に、トップエントリの獲得したブックマーク数の推移のチャートを加えます。
// ==UserScript== // @name chart of Hatena::Bookmark::24H // @namespace http://anond.hatelabo.jp/ // @include http://hatebu24h.ashitano.in/* // ==/UserScript== var url = unescape("http://chart.apis.google.com/chart?chs=160x60%26cht=ls%26chd=t:"); url = url + $X("//div[@class='clocktxt']", Array).map(function(s){return s.firstChild.nodeValue}).join(","); //var id = $X("//h3/a/@href")[0].nodeValue; //url = url + $X("//div[@class='entrytitle' or @class='entrytitle2'][.//a[@href='"+id+"']]/../preceding-sibling::div[1]", Array).map(function(s){return s.textContent.match(/\d+/)}).join(","); var before = makeElements({ nodeName: "div", className: "sidebox", childNodes: [{ nodeName: "div", className: "sidetitle", innerHTML: "Recent top entry chart" },{ nodeName: "div", className: "sidetitle", childNodes: { nodeName: "img", src: url } }] }); var after = $X("//div[@class='sidebox']", Array)[0]; after.parentNode.insertBefore(before, after); // util // var 0.01 function makeElements(obj) { if (typeof obj != "object") return document.createTextNode(obj); if (obj instanceof Array) return obj.map(makeElements); var node = document.createElement(obj.nodeName); delete obj.nodeName; if (obj.childNodes) { [].concat(makeElements(obj.childNodes)).forEach(node.appendChild, node); delete obj.childNodes; } function extend(dst, src) { for (var i in src) { if (typeof src[i] == "object" && dst[i] && typeof dst[i] == "object") extend(dst[i], src[i]); else node[i]=obj[i]; } } extend(node, obj); return node; } // by http://lowreal.net/blog/2007/11/17/1 // $X(exp); // $X(exp, context); // $X(exp, type); // $X(exp, context, type); function $X (exp, context, type /* want type */) { if (typeof context == "function") { type = context; context = null; } if (!context) context = document; var exp = (context.ownerDocument || context).createExpression(exp, function (prefix) { var o = document.createNSResolver(context).lookupNamespaceURI(prefix); if (o) return o; return (document.contentType == "application/xhtml+xml") ? "http://www.w3.org/1999/xhtml" : ""; }); switch (type) { case String: return exp.evaluate( context, XPathResult.STRING_TYPE, null ).stringValue; case Number: return exp.evaluate( context, XPathResult.NUMBER_TYPE, null ).numberValue; case Boolean: return exp.evaluate( context, XPathResult.BOOLEAN_TYPE, null ).booleanValue; case Array: var result = exp.evaluate( context, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); var ret = []; for (var i = 0, len = result.snapshotLength; i < len; i++) { ret.push(result.snapshotItem(i)); } return ret; case undefined: var result = exp.evaluate(context, XPathResult.ANY_TYPE, null); switch (result.resultType) { case XPathResult.STRING_TYPE : return result.stringValue; case XPathResult.NUMBER_TYPE : return result.numberValue; case XPathResult.BOOLEAN_TYPE: return result.booleanValue; case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: { // not ensure the order. var ret = []; var i = null; while (i = result.iterateNext()) { ret.push(i); } return ret; } } return null; default: throw(TypeError("$X: specified type is not valid type.")); } }
いまさらだがFizzBuzz。
1から100まで、3の倍数5の倍数云々って、全部定数の計算じゃね?
というところに気付き、自称メタプログラマー(略してメタグラマー)俺の血が騒いだ。
定数計算なら、それは実行時ではなくコンパイル時に行なわれるべきだ……。
#include <iostream> const int FIZZ_NUM = 3; const int BUZZ_NUM = 5; const int BEGIN_NUM = 1; const int END_NUM = 101; template<int N> struct Fizz { enum {PRINT = 0, NEXT = N + 1}; static void print() {} }; template<int N> struct Buzz { enum {PRINT = 0, NEXT = N + 1}; static void print() {} }; template<int N, bool ForB> struct Number {static void print() {std::cout << N;}}; template<> struct Fizz<FIZZ_NUM> { enum {PRINT = 1, NEXT = 1}; static void print() {std::cout << "Fizz";} }; template<> struct Buzz<BUZZ_NUM> { enum {PRINT = 1, NEXT = 1}; static void print() {std::cout << "Buzz";} }; template<int N> struct Number<N, true> {static void print() {}}; template<int N, int F, int B> struct FizzBuzz { static void print() { typedef ::Fizz<F> Fizz; typedef ::Buzz<B> Buzz; Fizz::print(); Buzz::print(); Number<N, Fizz::PRINT || Buzz::PRINT>::print(); std::cout << std::endl; FizzBuzz<N + 1, Fizz::NEXT, Buzz::NEXT>::print(); } }; template<int F, int B> struct FizzBuzz<END_NUM, F, B> {static void print() {}}; int main(int argc, char **argv) { FizzBuzz<BEGIN_NUM, 1, 1>::print(); return 0; }
ifなし%なしループ系なし、しかも実行時オーバーヘッドなし!(多分)
ああ、久しぶりにC++を触ったけど、やっぱC++のテンプレートってダメダメだな。20世紀の遺物といわざるを得ない。
君がもし21世紀のモテ系イケメンメタグラマーなら、21世紀のプログラミング言語、D言語を使うべきだ!
驚くべきことに、D言語はコンパイル時に関数が実行でき、その結果をソースコードとして取り込める!
ただし実行できるのは簡単な関数だけだけど……。
import std.stdio; // これでFizzBuzzを全部出力するコードを作るぜ! string makeFizzBuzzCode() { string code; for(int i = 1; i <= 100; ++i) { // 効率? コンパイル時にそんな配慮は要らん! if(i % 3 == 0 && i % 5 == 0) { code ~= "writefln(\"FizzBuzz\");\n"; } else if(i % 3 == 0) { code ~= "writefln(\"Fizz\");\n"; } else if(i % 5 == 0) { code ~= "writefln(\"Buzz\");\n"; } else { code ~= "writefln(" ~ static_itoa(i) ~ ");\n"; } } return code; } int main(string[] args) { // おまけで生成されたコードも見せるよ。 pragma(msg, makeFizzBuzzCode()); // 生成したコードを埋め込む。コピペみたいな感覚。 mixin(makeFizzBuzzCode); return 0; } // 以下ユーティリティ。このぐらい標準で欲しいな……。 /// 整数→文字列変換(コンパイル時) string static_itoa(int n) { if(n == 0) { return "0"; } // 10で割りながら余りを文字にして追加。桁が逆転した文字列になる。 string s; for(; n; n /= 10) { s ~= ("0123456789")[n % 10]; } // 桁位置を正常にする。相変わらず効率無視。 return static_reverse(s); } /// 配列リバース(コンパイル時) /// 実行時ならarray.reverseが使えるんだけどね……。 T[] static_reverse(T)(T[] s) { T[] result; foreach_reverse(c; s) { result ~= c; } return result; } // 心配なので静的ユニットテスト(笑) unittest { static assert(static_itoa(0) == "0"); static assert(static_itoa(10) == "10"); static assert(static_itoa(999) == "999"); static assert(static_itoa(9999) == "9999"); static assert(static_itoa(12345) == "12345"); static assert(static_itoa(314159265) == "314159265"); }
コンパイル結果
$ dmd -unittest fizz_buzz.d writefln(1); writefln(2); writefln("Fizz"); writefln(4); writefln("Buzz"); writefln("Fizz"); writefln(7); writefln(8); writefln("Fizz"); writefln("Buzz"); writefln(11); writefln("Fizz"); writefln(13); writefln(14); writefln("FizzBu(ry
出力結果は略。
さすがD言語!C++やJavaやC#にできない事を平然とやってのけるッ
そこにシビれる!あこがれるゥ!
というか、
writefln(1); writefln(2); writefln("Fizz"); writefln(4);
もうwritefln(出力関数)要らなくね?
修正。
// これでFizzBuzzを全部出力するぜ! string makeFizzBuzzCode() { string code; for(int i = 1; i <= 100; ++i) { // 効率? コンパイル時にそんな配慮は要らん! if(i % 3 == 0 && i % 5 == 0) { code ~= "FizzBuzz\n"; } else if(i % 3 == 0) { code ~= "Fizz\n"; } else if(i % 5 == 0) { code ~= "Buzz\n"; } else { code ~= static_itoa(i) ~ "\n"; } } return code; } int main(string[] args) { // もうコンパイル時のメッセージしか出さない。(笑) pragma(msg, makeFizzBuzzCode()); return 0; }
コンパイル結果。
$ dmd -unittest fizz_buzz.d 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBu(ry
実行するまでもなく結果が出力された。つまり実行時間ゼロ、ということは……
世 界 最 速
みんな使おうD言語!
http://www.kmonos.net/alang/d/1.0/index.html(1.0。こっちの方が安定してる?)
パッヘルベル「3つのヴァイオリンと通奏低音のためのカノンとジーグ ニ長調」
(独: Kanon und Gigue in D-Dur für drei Violinen und Basso Continuo)
1曲目の「Canon in D major」はたぶんクラシックの中で一番有名な曲
バッハの「G線上のアリア」(Air on the G String)
the pillowsの6枚目アルバム「LITTLE BUSTERS」から。
ASIAN KUNG-FU GENERATIONのシングル。鋼の錬金術師のOP
消してえーリライトしてえー
だんだん俗っぽくなってるのは気のせいですか?
これでおしまいだよ
(require 'cl) ; for cl-seq (defvar sangels-movies-dir nil) (defvar sangels-player "c:/Program Files/GRETECH/GomPlayer/GOM.exe") (defvar sangels-sort-by 'sangels-sort-by-rate) (defvar sangels-rate-file "~/.emacs.d/.sangels/rate") (defvar sangels-buffer "*sangels*") (defvar sangels-thumbnail "00_thumbnail.jpg") (defvar sangels-m3u "00_movies.m3u") (defface sangels-name '((t (:family "fixed" :weight bold :height 3.0))) "") (defface sangels-rate '((t (:family "fixed" :weight bold :height 1.5))) "") (defvar sangels-mode-map (let ((map (make-sparse-keymap))) (define-key map "n" 'next-line) (define-key map "p" 'previous-line) (define-key map (kbd "RET") 'sangels-select) (define-key map (kbd "SPC") 'sangels-select) (define-key map "q" 'sangels-quit) (define-key map "+" 'sangels-rate-plus) (define-key map "-" 'sangels-rate-minus) map)) (defvar sangels-mode-hook nil) (defvar sangels-highlight-overlay nil) (defvar sangels-rate-alist nil) (defconst sangels-rate-max 6) (defun sangels-insert-movies () (save-excursion (let* ((inhibit-read-only t) (files (remove-if-not (lambda (x) (and (not (member (file-name-nondirectory x) '("." ".."))) (file-directory-p x) (member sangels-thumbnail (directory-files x)))) (directory-files sangels-movies-dir t))) (ids (mapcar 'file-name-nondirectory files))) (erase-buffer) (setq ids (sangels-sort-ids ids)) (dolist (id ids) (let ((file (expand-file-name id sangels-movies-dir)) (pos (point))) (insert-image-file (expand-file-name sangels-thumbnail file)) (end-of-line) (insert (propertize (format "%-15s " id) 'face 'sangels-name)) (sangels-insert-rate id) (insert "\n") (put-text-property pos (point) 'sangels-id id)))))) (defun sangels-sort-by-name (a b) (string< a b)) (defun sangels-sort-by-rate (a b) (or (> (sangels-rate a) (sangels-rate b)) (sangels-sort-by-name a b))) (defun sangels-sort-ids (ids) (sort ids (or sangels-sort-by 'sangels-sort-by-name))) (defun sangels-insert-rate (id) (let ((rate (sangels-rate id))) (insert (propertize (concat (make-string rate ?★) (make-string (- sangels-rate-max rate) ?☆)) 'sangels-rate t 'face 'sangels-rate)))) (defun sangels-current-id () (get-text-property (point) 'sangels-id)) (defun sangels-play-movie (movie) (let ((explicit-shell-file-name "cmdproxy") (shell-file-name "cmdproxy")) (apply 'call-process-shell-command "start" nil "*tmp*" nil (mapcar (lambda (x) (concat "\"" x "\"")) (list sangels-player (unix-to-dos-filename movie)))))) (defun sangels-select () (interactive) (let ((id (sangels-current-id))) (when id (sangels-play-movie (expand-file-name sangels-m3u (expand-file-name id sangels-movies-dir)))))) (defun sangels-quit () (interactive) (kill-buffer sangels-buffer)) (defun sangels-rate (id) (or (cdr (assoc id sangels-rate-alist)) (/ sangels-rate-max 2))) (defun sangels-rate-save () (interactive) (let ((dir (file-name-directory sangels-rate-file))) (unless (file-exists-p dir) (make-directory dir t))) (with-temp-file sangels-rate-file (insert (pp-to-string sangels-rate-alist)))) (defun sangels-rate-load () (interactive) (when (file-exists-p sangels-rate-file) (with-temp-buffer (insert-file-contents sangels-rate-file) (goto-char (point-min)) (setq sangels-rate-alist (read (current-buffer)))))) (defun sangels-rate-plus (&optional n) (interactive "p") (setq n (or n 1)) (let* ((id (sangels-current-id)) (cell (assoc id sangels-rate-alist))) (unless cell (setq cell (cons id (sangels-rate id))) (setq sangels-rate-alist (cons cell sangels-rate-alist))) (setcdr cell (+ (cdr cell) n)) (save-excursion (let ((inhibit-read-only t)) (beginning-of-line) (goto-char (next-single-property-change (point) 'sangels-rate)) (delete-region (point) (next-single-property-change (point) 'sangels-rate)) (sangels-insert-rate id))) (sangels-rate-save))) (defun sangels-rate-minus (&optional n) (interactive "p") (setq n (or n -1)) (sangels-rate-plus (- n))) (defun sangels-post-command-hook () (save-excursion (move-overlay sangels-highlight-overlay (progn (move-beginning-of-line 1) (point)) (progn (move-end-of-line 1) (forward-line) (point)) (current-buffer)))) (defun sangels-mode () (interactive) (kill-all-local-variables) (use-local-map sangels-mode-map) (setq sangels-highlight-overlay (make-overlay 0 0)) (overlay-put sangels-highlight-overlay 'face 'highlight) (overlay-put sangels-highlight-overlay 'evaporate t) (make-local-variable 'post-command-hook) (add-hook 'post-command-hook 'sangels-post-command-hook nil t) (setq major-mode 'sangels-mode) (setq mode-name "Sangels") (run-mode-hooks 'sangels-mode-hook) (set-buffer-modified-p nil) (setq buffer-read-only t)) (defun sangels (&optional arg) (interactive "P") (when (or arg (not sangels-movies-dir)) (setq sangels-movies-dir (read-directory-name "movies dir: "))) (sangels-rate-load) (switch-to-buffer (get-buffer-create sangels-buffer)) (sangels-insert-movies) (sangels-mode)) (provide 'sangels)
結局概要表示機能追加した。unsafeWindow使いまくり。大丈夫かいな。
// ==UserScript== // @name Hatena Bookmark Tree Expander // @namespace http://anond.hatelabo.jp/ // @include http://b.hatena.ne.jp/entry/* // ==/UserScript== // <div class="info"> // <ul id="similar_entries" class="bookmarklist"> // <li></li> // </ul> // </div> // <div class="info"> // <ul id="referred_entries" class="bookmarklist"> // <li id="referred-entry-\d+"></li> // </ul> // </div> // <div class="info"> // <ul id="relation_diary" class="bookmarklist"> // <li id="diary-{id}-\d+"></li> // </ul> // </div> (function() { function main() { loadBookmarkCommentViewer(); similar.prototype.rootAppend(); referred.prototype.rootAppend(); } function HBTM(target) { this.target = target; this.targetXPath = "//ul[@id='"+target+"']/li"; this.targetRegExp = new RegExp('<ul id="'+target+'"(.|\\s)*?</ul>'); } HBTM.prototype = { openIcon: '<img width="15" height="15" class="icon" style="opacity: 0.6" src="http://anond.hatelabo.jp/images/common/open.gif"/>', closeIcon: '<img width="15" height="15" class="icon" style="opacity: 0.6" src="http://anond.hatelabo.jp/images/common/close.gif"/>', loadingIcon: '<img width="13" height="13" class="icon" src="http://anond.hatelabo.jp/images/common/loading.gif"/>', commentIcon: function(url) { return '<img class="hatena-bcomment-view-icon" src="http://r.hatena.ne.jp/images/popup.gif" onclick="iconImageClickHandler(this, \''+url+'\', event);">' }, create: function() { this.comment = document.createElement("span"); this.comment.innerHTML = this.commentIcon($X("string(descendant::a/@href)", this.node).value()); this.open = document.createElement("a"); this.open.href = "javascript:void(0)"; this.open.innerHTML = this.openIcon; this.close = document.createElement("a"); this.close.href = "javascript:void(0)"; this.close.innerHTML = this.closeIcon; this.close.style.display = "none"; this.loading = document.createElement("span"); this.loading.innerHTML = this.loadingIcon; this.loading.style.display = "none"; this.node.appendChild(this.comment); this.node.appendChild(document.createTextNode(" ")); this.node.appendChild(this.open); this.node.appendChild(this.close); this.node.appendChild(this.loading); this.open.addEventListener("click", bind(this.openAct, this), false); this.close.addEventListener("click", bind(this.closeAct, this), false); }, openAct: function() { this.open.style.display = "none"; if (this.tree) { this.tree.style.display = "block"; this.close.style.display = "inline"; } else { this.loading.style.display = "inline"; this.load(); } }, closeAct: function() { if (this.tree) { this.tree.style.display = "none"; this.close.style.display = "none"; this.open.style.display = "inline"; } }, load: function() { var url = $X("string(descendant::a[starts-with(@href, '/entry/')]/@href)", this.node).value(); GM_xmlhttpRequest({ method: "GET", url: "http://b.hatena.ne.jp"+url, onload: bind(this.loadCallback, this) }); }, loadCallback: function(result) { var match = result.responseText.match(this.targetRegExp); if (match) { var sandbox = document.createElement("div"); sandbox.innerHTML = match[0].replace(this.target,""); this.tree = sandbox.firstChild; } else { this.tree = document.createElement("ul"); } this.append(); this.loading.style.display = "none"; this.close.style.display = "inline"; }, append: function() { this.tree.style.backgroundColor = "transparent"; this.tree.style.listStyleType = "circle"; this.node.appendChild(this.tree); $X("li", this.tree).each(function(n) { var a = $X("a",n).node(); var c = $X("count(//li/a[@href='"+a.href+"'])").value(); if (c > 1) n.parentNode.removeChild(n); }); $X("li", this.tree).each(bind(function(node){new this.constructor(node)}, this)); }, rootAppend: function() { $X(this.targetXPath).each(bind(function(node){new this.constructor(node)}, this)); } }; function similar(node) { this.node = node; this.create(); } similar.prototype = new HBTM("similar_entries"); similar.prototype.constructor = similar; function referred(node) { this.node = node; this.create(); } referred.prototype = new HBTM("referred_entries"); referred.prototype.constructor = referred; function loadBookmarkCommentViewer() { var head = document.getElementsByTagName("head")[0]; var script = document.createElement("script"); script.type = "text/javascript"; script.src = "http://b.hatena.ne.jp/js/BookmarkCommentViewerAllInOne.1.2.js"; head.appendChild(script); var css = document.createElement("link"); css.rel="stylesheet"; css.href="http://d.hatena.ne.jp/css/base.css"; css.type="text/css"; css.media="all"; head.insertBefore(css, head.firstChild); window.addEventListener("load",function(){ var BCV = unsafeWindow.BookmarkCommentViewer; BCV.options['screenshot'] = true; var asyncCommnetView = BCV.asyncCommnetView; BCV.asyncCommnetView = function(url, onCompleteCallback) { var div = asyncCommnetView(url, function(){ onCompleteCallback.apply(this, arguments); new unsafeWindow.Ten.XHR("http://b.hatena.ne.jp/entry/rss/"+url, {}, function(result) { if (! result.responseText.match(/<description>(.*?)<\/description>/)) return; if (! RegExp.$1) return; // var desc = document.createTextNode("desc: "+RegExp.$1); var desc = document.createElement("li"); desc.appendChild(document.createTextNode("desc: "+RegExp.$1)); div.lastChild.insertBefore(desc,div.lastChild.getElementsByTagName("li")[0]); }); }); return div; }; BCV.asyncCommnetView.origin = asyncCommnetView; }, false); } function bind(f,o) {return function() {return f.apply(o, arguments)}} function $X(xpath, context) { if (!(this instanceof $X)) return new $X(xpath, context); this.xpath = xpath; this.context = context || document; } $X.prototype = { evaluate: function() { var result = document.evaluate(this.xpath, this.context, null, this.type, null); switch (result.resultType) { case XPathResult.STRING_TYPE : return result.stringValue; case XPathResult.NUMBER_TYPE : return result.numberValue; case XPathResult.BOOLEAN_TYPE: return result.booleanValue; case XPathResult.FIRST_ORDERED_NODE_TYPE: return result.singleNodeValue; } return result; }, node: function() { this.type = XPathResult.FIRST_ORDERED_NODE_TYPE; return this.evaluate(); }, value: function() { this.type = XPathResult.ANY_TYPE; return this.evaluate(); }, each: function(func) { this.type = XPathResult.ORDERED_NODE_SNAPSHOT_TYPE; var result = this.evaluate(); for (var i=0; i<result.snapshotLength; i++) func(result.snapshotItem(i)); } }; main(); })();