こんにちは。エクセルソフトの田淵です。
最初は
LINQでList<string> srcをList<string> filterのどれかが該当する結果を取得したいんですけど、どうやるのが良いんでしょうか?
— 田淵 義人@エクセルソフト (@ytabuchi) 2015, 8月 3
これで色々教えてもらいました。 今日は今日で LINQ で任意の文字を含む/含まないコレクションを作成するメモ - Xamarin 日本語情報 について HashSet が良いよとコメントを頂きました。
識者の皆様に囲まれて嬉しいです涙 色々な書き方があるんだなーということで試してみましたのでメモを残しておきます。
サンプル
準備
1000個の i の倍数を List, HashSet で用意します。
private HashSet<string> AddItems(HashSet<string> set, int i) { foreach (var j in Enumerable.Range(0, 1000)) { set.Add($"Item {i * j}"); } return set; } private List<string> AddItems(List<string> list, int i) { foreach (var j in Enumerable.Range(0, 1000)) { list.Add($"Item {i * j}"); } return list; }
具体的には 2 の倍数と 3 の倍数で用意しました。3 の倍数で 2 の倍数をフィルタしたいと思います。
list2 = new List<string>(); AddItems(list2, 2); hash2 = new HashSet<string>(); AddItems(hash2, 2); filter = new HashSet<string>(); AddItems(filter, 3);
パフォーマンス調査!
2015/8/26 追記:
計測値の大半が UI 描画では?というご指摘を頂きました。確かにそうだ!orz 慣れない事するから… 別途 Xamarin.Forms で ListView の Cell により描画の違いはあるか?などエントリーを書いてみたいと思います。今回は UI もごっちゃまぜでのあまり意味のないパフォーマンス調査ということでご容赦ください…!
Any:
var res = from s2 in list2 where filter.Any(fs => s2.Equals(fs)) select s2; foreach (var item in res) { listData.Add(item); }
Join:
var res = from s2 in list2 join fs in filter on s2 equals fs select s2; foreach (var item in res) { listData.Add(item); }
Intersect:
var res = list2.Intersect(filter); foreach (var item in res) { listData.Add(item); }
HashSet.IntersectWith:
hash2.IntersectWith(filter); foreach (var item in hash2) { listData.Add(item); }
結果
折角 Xamarin.Forms でやっているので Android, iOS, Windows Phone で計測結果を出しました。
iOS
Any 平均: 406ms
Join 平均: 356ms
Intersect 平均: 366ms
HashSet 平均: 356ms
Android
Any 平均: 235ms
Join 平均: 118ms
Intersect 平均: 118ms
HashSet 平均: 111ms
Windows Phone
Any 平均: 198ms
Join 平均: 22ms
Intersect 平均: 24ms
HashSet 平均: 21ms
所感
iOS が Any でも対して遅くないのは意外でしたが、早いはずの Join、Intersect などが遅いとも言えそうです。AOT の Mono だからですかね…?
Windows Phone で Join, Intersect がめっちゃ早かったのも印象的でした。.NET に最適化されているということかなと。このあたりは流石ですね。(UI コントロールがキレイだったらよかったのに…!><)
次は
今回は 1次元配列どうしを比較しましたが、次は少しボリュームのある List, HashSet を 1次元の配列でフィルタするのに挑戦したいと思います。
参考資料
- MSDN: Enumerable.Intersect(TSource) メソッド (IEnumerable(TSource), IEnumerable(TSource)) (System.Linq)
- MSDN: HashSet(T) クラス (System.Collections.Generic)
- ジェネリックコレクション その7 HashSetとSortedSet (System.Collections.Generic) - Programming/.NET Framework/コレクション - 総武ソフトウェア推進所
Xamarin 気になった方は
是非 ダウンロード(直接) / ダウンロード(弊社経由) して触ってみてください。 学習用リソース や JXUG リンクページ に参考資料を纏めてますので併せてどうぞ。
Xamarin の情報が欲しい方はこのブログも購読いただいたりすると嬉しいです。
以上です。