basyura's blog

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

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 使えば即実行できるし便利。

労働過多からの休息

過去かつてない最悪な長時間労働により残業時間が通常の 3 倍。徹夜を繰り返しても案外いけるもんだなという知見を得たものの完全に生活リズムが崩れているので取り戻し中。戻すために今週は勝手に在宅勤務で引きこもり生活をしていたけど戻しきれていない。来週は流石に出社するかなぁ。でもそろそろ労組が動き出さないとおかしいレベルなのだが。あと人事も幹部社員になんか言ってるようだけど強制力がないのか役に立たない。稼働前から無理なことは分かっていたのだけど認められずの強制稼働。当たり前に問題点続出。解決しろとは言われても焦って出すので問題が広がる。人を投入しすぎると悪循環に陥るという教科書通りの問題を辿る。それをレビューで拾うのも無理。細かいところまで全体を知ってるわけではないし。問題にしてもらわないと困るので労働時間は全部打付けるけどな。んで、今年の後半は働かない (働けない)。

Surface Pro 欲しくなって来た

Core i5/8G 256G で 158,544 円 だもんなぁ。デザインも良くなってる。初期の Surface のイメージが先行していたけど、妙な厚さや野暮ったい感じがななってきてて良い感じだ。もうちょっと薄くなるといいなぁ。

Type Cover がすごく打ちやすかったのが一番驚いた。それに比べて MacBook Pro ときたら・・・。妙に手に吸い付く感じが気持ち悪い。少し凹んでるのでそのためなのか。打鍵感がよくなる考慮なのかもしれないけど気持ち悪さが先行する。Smart Keyboard の方がかなり打ちやすい印象。

Smart Keyboard はキーボードを前面に出す状態と背面に隠す二つの形態があるのだけどこれを切り替えるのが割と手間。「あれ、どう折りたたむんだっけ」ってなってる間にマグネットが外れてアーっとなることが多い。それに対して Surface は本体の背面に傾き調整の支え?がついてるので、キーボードが不要ならガッと外してしまえばいい。何より esc が有るのが良い。

iPad は iOSだけど、Surface Pro なら windows10 が動いてるわけだからキーカスタマイズや他のカスタマイズも自由にできるしなぁ。とりあえず Ctrl+P Ctrl+N で上下にカーソル移動できるだけで編集のやりやすさがかなり変わるんだけどなぁ。

iOS と macOS を1つにするのは厳しそうだけど、windows では windows phone が失敗した今となっては切り捨ててしまってデスクトップでもラップトップでもタブレットでも同じ os が動くことが強みになってきてる。普通にラップトップとして使えるし、タブレットとして “も” 使える。このシームレスさは強みだ。

ここまで書いて、メインマシン的に使うとなると開発がらみでメモリは 16G 欲しいのでっとなると・・・280,584 ・・・うぅ・・・。

せっかく iPad Pro を買ったので iOS11 でいろいろ変わるようなので期待したいところ。

Redmine - View Customize Plugin の編集時の高さを調整

View Customize Plugin は便利だけど、編集しようとするたびに毎回気になることがある。

編集するテキストボックスの高さが狭い。

毎回広げてから編集を開始するのが手間 (Github のページを見るとスクリーンショットは十分な領域が確保されているのだけど自分だけだったりするんだろうか)。

View Customize Plugin で View Customize Plugin の View を Customize する。

Path pattern : /view_customizes/*

$(document).ready(function() {
  $("#view_customize_code").css('min-height', '350px');
});

べんりぃ。いろんなことが View Customize Plugin で解決できて便利ね。沢山登録しすぎると重くなるかもしれないけど。最近のブラウザなら気にする必要ないか。実際気にならないし。

入門Redmine 第5版

入門Redmine 第5版