2010/11/27

[C#]DataTableの行を入れ替える

このエントリーをはてなブックマークに追加
DataTableの指定行を入れ替える方法です。
ソートとかしたいだけなら、DataViewを利用したほうが間違いなくいいのでそっちでお願いします。

DataTableの行の入れ替え


ソースコード

private bool swapRow(DataRow row1,DataRow row2) {
    if (row1.Table != row2.Table) {
        // 同じテーブルに所属している必要があります
        return false;
    }

    DataTable table = row1.Table;
    
    // ①
    // row1のコピーを作成
    int index1 = table.Rows.IndexOf(row1);
    DataRow newRow1 = table.NewRow();
    newRow1.ItemArray = row1.ItemArray;

    // row2のコピーを作成
    int index2 = table.Rows.IndexOf(row2);
    DataRow newRow2 = table.NewRow();
    newRow2.ItemArray = row2.ItemArray;

    // ②
    // コピーを入れ替えて挿入しつつ、元の行は削除
    table.Rows.InsertAt(newRow1, index2);
    table.Rows.Remove(row2);
    table.Rows.InsertAt(newRow2, index1);
    table.Rows.Remove(row1);
    return true;
}


それぞれに対応する新しい行を作成。行1と行2の内容をそれぞれ複製しておく。


複製行を入れ替えて挿入してつつ、元の行を抹消します。
行1の複製を行2の位置に挿入した後に、行2を消す。
同じく行2の複製を行1の場所に挿入した後に、行1を消す。


table.Rows.RemoveしてそのままrowをどこかにInsertAtしちゃえば、一見できそうに思うのですが、Removeした段階で、rowの内容が全部抹消されてしまうのです。


なお、この方法では、RowState.Deleted、RowState.Addedが発生するので注意。
DataTableのGetChangesメソッドという、変更行を取得するメソッドに引っかかってしまいます。悪しからず。

2010/11/18

[C#]クラスのインターフェースを調べる

このエントリーをはてなブックマークに追加
任意のクラスがどういうインターフェースを持っているのかを調べる方法です。
プログラミングに使用するほとんどの時間は、自分のクラスを制作するのと、使用するクラスを調べることに費やされるもの、と某書籍に書いていました。普段何気なく使用しているクラスに、本来どういう役割や機能が実装されているのかを知る手がかりになれば幸いです。

インターネット(msdn)で調べる


.netのクラスを単に調査したいときは一番手っ取り早い。クラス名でググれば、ほとんど出てきます。
しかし手っ取り早くはあるもののドキュメント一式をさらうまでもなく、そのときの要件に沿っているかどうかが知りたいだけのときがほとんどなので、ケースバイケースだったりします。もちろん、ちゃんと読んだほうがいいのですが。

String クラス (System)
http://msdn.microsoft.com/ja-jp/library/system.string(v=VS.85).aspx

isを使う(またはasを使う)

is/asを使うことでキャストが可能かどうか調べることができます。
Type type = typeof(string); // 仮に謎のクラスをTypeとします

// isを使う
if (type is ICloneable) {
    // typeにはIClonableが実装されている
}

//asを使う
ICloneable cloneable = type as ICloneable;
if (cloneable != null) {
    // typeにはIClonableが実装されている
}

is (C#)
http://msdn.microsoft.com/ja-jp/library/scekt9xw(VS.80).aspx

as (C# リファレンス)
http://msdn.microsoft.com/ja-jp/library/cscsdfbt(v=VS.80).aspx

インターフェースを自力でリストアップする

実装されているインターフェースをリストアップする関数を書きました。
基底クラスがある場合は、基底クラスにも潜って再帰的に調べます。
public IEnumerable<Type> GetInterfaces(Type type) {
    foreach(Type t in type.GetInterfaces()){
        yield return t;
    }

    if (type.BaseType != null) {
        foreach (Type t in GetInterfaces(type.BaseType)) {
            yield return t;
        }
    }
}

実行サンプル
stringクラスのインターフェースを列挙します。
foreach (Type t in GetInterfaces(typeof(string))) {
    Console.WriteLine(t.ToString());
}

結果。
System.IComparable
System.ICloneable
System.IConvertible
System.IComparable`1[System.String]
System.Collections.Generic.IEnumerable`1[System.Char]
System.Collections.IEnumerable
System.IEquatable`1[System.String]


`1[System.String]は、<System.String>のこと。つまりジェネリッククラスです。

2010/11/15

Googleのインスタントプレビュー

このエントリーをはてなブックマークに追加
Google「検索結果を直感的にわかりやすく。インスタント プレビュー新登場」
http://googlejapan.blogspot.com/2010/11/blog-post.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed:+GoogleJapanBlog+(Google+Japan+Blog)

検索結果のサイトプレビューが閲覧される機能が追加した、というか追加してしまった。

○○できるようになりました、とかなら解るのだけれど、「直感的にわかりやすく」なんていうキャッチーきわまりないコピーを見ると、自分で言うなよと思わず反発してしまうわけです。日本的なのかもしれないけれど、おこがましくはないのでしょうか。

裏で先に取得しにいくから、待たされないらしい、という、もはや非同期が多すぎて裏で何やってるのか解らないことばかりです。結局、非同期にする必要があるということは、「重たい処理」を誤魔化すためだということ。処理を無効化できるなら、そんなことも気にしなくてもいいのに。
さて、機能停止したいけれど、どうやればいいのだろう。上のページには何も書いてないしなー。
Googleドキュメントも、Googleの画像検索も勝手にどんどん変わる。ユーザーの都合なんて知ったことではないのですね。
まあもちろん何も変わらない状況がいいとは言わないけれど。
いやー。シンプルなページがよかったなー。

そんなことよりも。各サービスの上に出てくるバーのメニューを統一していただきたい。バラバラすぎる。
きっとヤキモキしつつも、諦めざるをえない事情があるんでしょうな。知らないけれど。

なんてことを言いつつも、もちろん、いつもお世話になっているのです。Googleさん、ありがとう。いや、本当に。
ちょっとくらい使いにくくなっても文句なんて言いませんよ。もちろん我慢しますとも。

2010/11/11

bootcampがYoutube終わりにフリーズする

このエントリーをはてなブックマークに追加
MacBookPro13に入ってるWindows7がちょくちょくフリーズする。カーソルまで固まってしまって、まったく何をしても受け付けなくなる。しばらく(1分くらい)経過すると何事もなかったかのようにカーソルが生き返る。

最近解ってきたのは、YouTubeやニコニコ動画などの動画を見ていたタイミングでこの現象に遭遇するということ。
回避策は結構単純で、動画が終わる前にブラウザごと閉じてしまえばいいのです。これでフリーズは防げる。一時停止してもフリーズするようです。さっと見てさっと消せば、基本的には問題ない。
もちろん、この現象はOSXでは出ないし、bootcamp以外の普通のWindowsでも見たことがない。特有の現象のようです。

常用ブラウザはChromeですが、FireFoxでも同じ現象が確認できるので、ブラウザ依存とも言えないようです。
JavaAppletの動作時にも似たようなフリーズ現象が発生する。画面を切り替えるたびに固まるような気がする。結構ひどかった。

フリーズといっても、モニタに反映されていないだけで、裏で処理は続行しているみたいです。
調べてみると、情報がとても少なくて参ったけれど、どうやらbootcampのグラフィックドライバの問題ではなかろうかという噂があるようで、確かにそんな感じではあります。
気になるのは、100%再現するわけではないということ。再現するときは、もう一回繰り返しても再現するようです。再起動すると大体なおる。このあたりがわりと曖昧で、条件がよくわからない。

bootcamp3.1です。現時点の最新です。
Appleの対応待ちか?

なお、この現象は、少なくともマシンのスペックの低さによるものでないようです。メモリ増設したってフリーズをとめることはできないでしょう。
本当に低スペックでも、カーソルが固まるようなフリーズってしないですよね。もっさりはするだろうけど、その時もカーソルは動く。

普段このマシンで音鳴らしたり動画みたりするようなことはあまりないので、幸運にも全然気にならないです。
たまに、最後まで見せられるような興味深い動画に出くわすと、ブラウザ閉じる前に、動画停止して、そのままフリーズしてしまって、やっちゃったなーと思うことはある。まあそれは、その動画がいい動画であったことの証です。フリーズでせっかく張り詰めた集中力がお釈迦になるのはいただけないか。

もう一つ。
bootcampによるWindows7のスリープ解除後、キーボードライトがマックスに点灯することがあるのもなんとかしていただきたい。
普段、消していて、使うことはめったに無いのに毎回消灯作業する必要が出て、めんどい。これも再現するときと、しないときが判別できません。何の弾みか判らないけれど、おもむろに突然点灯しだしたりもする。
後は、わりと普通に使えて満足です。この2点だけは納得いってない。

:追記 2011/05/20
YouTubeからのフリーズ問題は、Bootcamp3.2にアップデートすることで解決した(と思われる)。

2010/11/05

javascriptでストップウォッチを実装する

このエントリーをはてなブックマークに追加
処理速度なんかを計るときに利用していたコードです。

javascriptによる処理時間を計測



処理時間を計測するときは下のようなコードになるかと思われます。
var st = new Date(); // 処理開始。

// 処理

var et = new Date(); // 処理終わり。
alert(et - st); // 経過時間をミリ秒で表示。


何がダメってわけでもないです。やってることは同じなので。
それがこう書ける。

var sw = new Stopwatch();
sw.start(); // 処理開始。

// 処理

sw.pause(); // 処理終わり。
alert(sw.getStamp()); // 経過時間をミリ秒で表示。


まあ、長くなってるような気がしないでもない。何がメリットかって、改めて見ると別にメリットなんてないですね。どうやっても処理時間なんてなんでも計れるんだし。まあいいや。
このストップウォッチは、C#のStopWatchクラスを模してます。中断ができる点が工夫で、あと整形して表示できる。つまり、一回計測を止めて、続きから計測を再開するようなコードが容易く書けるわけです。

var sw = new Stopwatch();
sw.start(); // 処理1開始。

// 処理1

sw.pause(); // 処理1終わり。

alert("ここの待機時間は計測されない");

sw.start(); // 処理2開始。
// 処理2
sw.pause(); // 処理2終わり。
alert(sw.getStamp()); // 処理1+処理2の経過時間をミリ秒で表示。


ストップウォッチ(コード)


やってることはすごくシンプルなので、コードも短いです。

// ■ StopWatch
function StopWatch()
{
var self = this;
var stamp = 0;
var startTime = null;
self.start = function ()
{
startTime = new Date();
};
self.pause = function ()
{
stamp = self.getStamp();
startTime = null;
};
self.reset = function ()
{
stamp = 0;
startTime = null;
};
self.getStamp = function ()
{
if (startTime == null) {
return stamp;
}
return new Date() - startTime + stamp;
};
self.getStampString = function ()
{
var val = self.getStamp();
// hh:MM:ss.SSSに整形(hが多いとき、SSSがないときは桁がずれる)
var s = (val % (60 * 1000)) / 1000;
var m = ((val / (60 * 1000)) | 0) % 60;
var h = ((val / (60 * 60 * 1000)) | 0) % 60;
if (s < 10) {
s = "0" + s;
}
if (m < 10) {
m = "0" + m;
}
if (h < 10) {
h = "0" + h;
}
return "" + h + ":" + m + ":" + s;
};
}


・メソッド




start計測を始めます。
pause計測を一旦止めます。
reset計測をリセットします。
getStamp経過時間をミリ秒単位で返します。
getStampString経過時間を整形して返します。

※整形については、コード見ればお分かりの通り、なんちゃってです。桁固定は保証していません。しかしデバックするだけならこれで十分。

・使用方法
/* ストップウォッチの使用方法 */
var sw = new StopWatch();
sw.start();
alert("計測中");
sw.pause();
alert("待機してた時間 " + sw.getStampString());