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

不動産屋のラノベ読み

不動産売買営業だけどガチガチの賃貸派の人のブログ

真理値表から論理式を作ると一見何をしてるのか分からないコードが書ける

WEB作成

 
またまた不動産屋に関係ない話ですが。
人力検索

日付の配列があったときに、
$day = array(
'2013-08-30',
'2013-08-31',
'2013-09-01',
'2013-09-02',
'2013-09-05',
'2013-09-06',
'2013-09-10',
'2014-01-01',
)

このように表示したいです。
'2013年8月30日09月2日、9月5日06日、9月10日、2014年1月1日'

PHP で複数の日付を「期間表記」に変換するコードを教えてくださ… - 人力検索はてな

という面白そうな質問があったので、
本日のコーディング大会会場です。 ... - 人力検索 - Lhankor_Mhy - はてなハイク
とハイクで回答を呼びかけてみました。
いろいろな回答があったのですが、アルゴリズム的には前項の値を持ってぐるぐる回す、というわりと普通のものでした。
 
で。
もうすこし変わった処理を思いついたので記事にします。
 

1ビットシフトして反転して論理積をとる

↑処理的にはこのタイトルのようなことをしています。
 
まず、日付を2進数各ケタに割り当てて、その日付が存在するビットを立てた値を作ります。
始期と終期が取れればいいので、同じ値で連続するビットのエッジを検出しよう、と思いました。ローテートしてXORあたりでいけると思いましたが、連続しない日付が取れなかったのでダメでした。
で、学生時代を思い出して真理値表を書きました。

入力 シフト 出力
0 0 0
0 1 0
1 0 1
1 1 0

ここから論理式を書くのですが、やり方をすっかり忘れていたので「真理値表 論理式」でググりました(w
で、書いたのが↓この部分です。

var spanFlag = dateFlag.map(function(v, i){
    return this[i]&&!this[i-1] + ( this[i]&&!this[i+1] )*2;
}, dateFlag);

PHPとはどうしても仲良くなれないので、JavaScriptで書きました*1。キャリーつきローテートで処理をすればいいのでしょうけれど、をどう書いたらいいのか分からなかったので2値配列です。また処理の都合上、実際には始期と終期のフラグを0〜3にマッピングしてます。
 
コード全体はこちら。
http://jsfiddle.net/Zzd6L/

//問題
var day =[
'2013-08-30',
'2013-08-31',
'2013-09-01',
'2013-09-02',
'2013-09-05',
'2013-09-06',
'2013-09-10',
'2014-01-01'
]

//出力関数配列
var showSpan = [
    function(day){return ''},
    function(day){return day+'〜'},
    function(day){return day+'、'},
    function(day){return day+'、'}
]

//Dateオブジェクト拡張
var toStringEscape = Date.prototype.toString;
Date.prototype.toString = (function(){
    var prev = new Date('1970-01-01');
    return function(){
        var str;
        var y=this.getFullYear().toString();
        var m=(this.getMonth()+1).toString();
        var d=this.getDate().toString();
        var prev_y=prev.getFullYear().toString();
        var prev_m=(prev.getMonth()+1).toString();
        if (y!=prev_y) {
            str = y+'年'+m+'月'+d+'日';
        } else if (m!=prev_m) {
            str = m+'月'+d+'日';
        } else {
            str = d+'日';
        }
        prev = this;
        return str;
    }
})()
Date.prototype.serialize = function(){
    return this/1000/24/3600|0;
}
Date.prototype.unSerialize = function(serial){
    return new Date( serial*3600*24*1000 );
}

//
var serializedDay = day.map(function(v){
    return (new Date(v)).serialize();
});
var dateFlag=[];
for( var i=0; i < ( serializedDay.slice(-1)[0] - serializedDay[0] ); i++ ) dateFlag[i]=0;
for( var i=0; i < serializedDay.length; i++ ) dateFlag[ serializedDay[i] - serializedDay[0] ] = 1;
var spanFlag = dateFlag.map(function(v, i){
    return this[i]&&!this[i-1] + ( this[i]&&!this[i+1] )*2;
}, dateFlag);
var str = spanFlag.map(function(v, i){
    return showSpan[ spanFlag[i] ]( new Date().unSerialize( i+serializedDay[0] ) );
}, dateFlag);
alert( str.join('').slice(0,-1) );

//退避したtoStringメソッドを戻す
Date.prototype.toString = toStringEscape;

 

で?何のためにこの記事を書いたの?

↑ちょっと変わったこと思いついたら他人に見せたいじゃないですかー

*1:配列の外側にアクセスしてるのにぬるぽしないJavaScript素敵です(w