basyura's blog

あしたになったらほんきだす。

孔明のヨメ

面白いので一気読みしてしまった。年に 1 冊ペースっぽいので待ち遠しいところ。また吉川英治の三国志を読み直してもいいなぁと思うが何回目なのかも思い出せない (その割に内容を覚えているような覚えていないような)。

孔明のヨメ。 1巻 (まんがタイムコミックス)

孔明のヨメ。 1巻 (まんがタイムコミックス)

孔明のヨメ。 2巻 (まんがタイムコミックス)

孔明のヨメ。 2巻 (まんがタイムコミックス)

孔明のヨメ。 3巻 (まんがタイムコミックス)

孔明のヨメ。 3巻 (まんがタイムコミックス)

孔明のヨメ。 4巻 (まんがタイムコミックス)

孔明のヨメ。 4巻 (まんがタイムコミックス)

孔明のヨメ。 5巻 (まんがタイムコミックス)

孔明のヨメ。 5巻 (まんがタイムコミックス)

孔明のヨメ。 6巻 (まんがタイムコミックス)

孔明のヨメ。 6巻 (まんがタイムコミックス)

孔明のヨメ。 7巻 (まんがタイムコミックス)

孔明のヨメ。 7巻 (まんがタイムコミックス)

cVim を fork

cVim はまだ痒いところに手が届かない感があるけど便利・・・なのだけど気になる挙動がまぁまぁある。
自分で直せばいいのだけど、

  • 拡張機能がバージョンアップされるたびに強制的に戻ってしまうのでオレオレパッチを毎回あてるのがめんどくさい
  • Pull Request を送るにしても採用される程度に作り込むのがめんどくさい

である。

今までそれでもいいかと思っていたのだけど、コマンドバーで Enter すると日本語入力の確定でも実行されてしまうのが新たに?発動したのもあって (mac だけかなぁ)、さすがにだるくなったので fork した。

やり方

  • https://github.com/1995eaton/chromium-vim をどこかのディレクトリに clone
  • 必要に応じてソースを修正
  • 拡張機能の管理画面を開く
  • デベロッパーモードにチェックを入れる
  • パッケージ化されていない拡張機能を読み込むで clone したディレクトリを指定する

細かい所で気になるところはまぁまぁあるけど、いまのところ満足。これで様子を見る。

人工知能の本

人工知能の核心 (NHK出版新書)

人工知能の核心 (NHK出版新書)

AI がー、AI で解決できないのかーっていつも通り流行乗って言うだけのお偉いさんの相手するのはだるいのだけど、正直人工知能の定義が分からん。Web サーバで動いてればクラウドになっちゃったように、ソフトウェアで処理させて何かしらの結果が出たら過程はどうであれ AI でやりましたって言っても通じそう感ある。

実践的な本をチラ見してみると数式がどうのこうので心が折れたので概要から入ってみる。

C# - インデックス付き Select

Enumerable.Select(TSource, TResult) メソッド (IEnumerable(TSource), Func(TSource, Int32, TResult)) (System.Linq)

public static IEnumerable<TResult> Select<TSource, TResult>(
    this IEnumerable<TSource> source,
    Func<TSource, int, TResult> selector
)

要素が 1 個でも 1000 個でも変わるのは 1 ms 程度だったという驚き。

var list = Enumerable.Range(0, 1).Select(v => v.ToString()).ToList();

var watch = Stopwatch.StartNew();
var i = 0;
foreach (var v in list)
{
    i ++;
}
watch.Stop();
Console.WriteLine(watch.Elapsed);

watch = Stopwatch.StartNew();
foreach (var v in list.Select((value, index) => new { value, index }))
{
    Console.WriteLine(v.value);
    Console.WriteLine(v.index);
}
watch.Stop();
Console.WriteLine(watch.Elapsed);

わざわざカウンターを別に設けなくても良かったのね。記述が冗長になる気はするけど・・・どっちがいいのかなぁ。思い切って for 使ってもいい気がしないでもない。

for (int i = 0 ; i < list.Count; i++)
{
    var value = list[i];
}

ループの先頭で変数に入れてしまえば添字の書き間違いなんてそうそう起こらないだろうし。 てなことを今更ながら考えてたりする今日このごろ。

blog 等では列数確保のために var を使うけど、仕事で書くときは型をきっちり書く派。この変数、メソッドの戻り値がどういう型なのか気になるし、調べるためにマウスカーソルを当てるのもだるいので最初から見えてたほうがいいじゃん派。var を使ったほうがきれいに見えるのだけど・・・考える上ではあまり便利とは思えないのであった。

C# - LINQ でループの回り具合を再確認

LINQ 大好きなのはいいんだけど基本的に for で回してるのと同じだってことを認識していない人が多くて困る。魔法か何かと勘違されてる。これに起因してパフォーマンス悪化しまくり。LINQ 便利で使うのだけど、LINQ がない時にそんなにループで回すこと多かったかな?という疑問。隠蔽されることで、”とりあえず List” にしといて LINQ で取ればいいやで実装する人がやけに多い。その都度注意するのだけど分かったのか分かってないのか減らない。メソッドで引数を受けるときも IEnumerable で受ければいいのに List をにしてるからわざわざ ToList が必要だったり、必要ないのに ToList したりなかなかのカオス。

実際どういう動きになるのかを改めて確認してみる。

Where → Select したものを Any と foreach で呼び出す

Any or foreach を使うたびに LINQ が評価される。 Where を評価するための判断材料の生成コストや、Select で変換するためのコストが高いとその分パフォーマンスが悪化することになる。

コード

var list = new List<string>(){ "0", "1", "2", "3", "4" };

var targets = list.Where(v => {
    Console.WriteLine("Where  => " + v);
    return true;
}).Select(v => {
    Console.WriteLine("Select => " + v + "\n");
    return v;
});

Console.WriteLine("----- Any -----");
targets.Any();

Console.WriteLine("----- foreach -----");
foreach (var target in targets) {
}

出力

----- Any -----
Where  => 0
Select => 0

----- foreach -----
Where  => 0
Select => 0

Where  => 1
Select => 1

Where  => 2
Select => 2

Where  => 3
Select => 3

Where  => 4
Select => 4

foreach で止めてからの foreach

当たり前だけど?頭から再度回る。

コード

var list = new List<string>(){ "0", "1", "2", "3", "4" };

var targets = list.Where(v => {
    Console.WriteLine("Where  => " + v);
    return true;
}).Select(v => {
    Console.WriteLine("Select => " + v + "\n");
    return v;
});

Console.WriteLine("----- foreach 1 -----");
foreach (var target in targets.Select((v, i) => new { v, i }))
{
    if (target.i == 3)
    {
        Console.WriteLine("Break");
        break;
    }
}

Console.WriteLine("----- foreach 2 -----");
foreach (var target in targets.Select((v, i) => new { v, i }))
{
}

出力

----- foreach 1 -----
Where  => 0
Select => 0

Where  => 1
Select => 1

Where  => 2
Select => 2

Where  => 3
Select => 3

Break
----- foreach 2 -----
Where  => 0
Select => 0

Where  => 1
Select => 1

Where  => 2
Select => 2

Where  => 3
Select => 3

Where  => 4
Select => 4

List の ToList()

自身を返すと思いきや別インスタンスの List を返している。安全側に倒してるんだろう。

Reference Source

public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source) {
    if (source == null) throw Error.ArgumentNull("source");
    return new List<TSource>(source);
}

まとめ

現実問題としては LINQ による遅延評価のメリットを出す機会よりも、抽出した内容に対して複数の絞り込みをするケースが多いために ToList をせざるをえない機会が多い。そうなってしまうのはそもそものデータ構造やロジックの問題なので根が深そう。

試した環境は mac だけど、 brew install mono で入るし vim で quickrun 使えば即実行できるし便利。