KotlinでC#のLINQっぽいのを実装してみた
どうも最近Kotlinを使い始めたJava(Android)からの移行者です
普段はC#使ってます
C#のLINQ便利でいいですよね!
KotlinにもfilterやmapなどJavaのStreamライクなメソッドはありますがfilterなどのソースを見に行くとどうも遅延実行していないっぽいのです
追記)遅延実行するリスト操作関数としてSequenceとその拡張関数が用意されてました。すいません(>_<)
Sequence作成にはasSequence()関数を呼べばいいみたいです、なのでLINQライクな関数名がいいという方向けの記事になります
ということで自作してみました!
ちなみに遅延評価とよく聞くのですが
遅延評価いうなキャンペーンとかどうか - ぐるぐる~
によるとこの種の動作は遅延評価と表現するのは正しくないようです
ではどう表現するのか?となるのでC#のLINQ Whereのリファレンスを見に行くと
This method is implemented by using deferred execution.
このメソッドは遅延実行を使用して実装されます。
と表記されているので、ここでは遅延実行と表現します
注意
- 勉強足らずなので内容には間違いがあるかもしれません
- 関数とメソッドがごちゃまぜになっています
- なぜKotlinは関数なのか
- 圧倒的ドキュメント、コメント不足の内容になっています
- テストコードが不足しています
- mavenとかgradleよくわかっていない人が作ってます←おいw
- stdlibは1.0.0-rc-1036です
KLinq
ほぼC#のLINQと同じ名前、引数で遅延実行を実装しているライブラリです
ソース
ソースはGithubで公開しています
repositories {
mavenCentral()
maven { url "https://raw.github.com/MeilCli/KLinq/master/klinq/repository" }
}
dependencies {
compile 'meilcli:klinq:1.2'
}
で利用できるはずです
使い方
import com.twitter.meil_mitu.klinq.*
お決まりのおまじない()
var linq = arrayOf(1,2).toEnumerable()
linq.where{ x -> x>0}...
toEnumerable()以外だいたいC#のと同じ感覚でイケるはずです
(上のは分離させてるけどもちろんメソッドチェーンできます)
...あれ、この場合は関数じゃなくてメソッドでよかったのかな....
Enumerable.range(0,10)
(0..9).toEnumeable()
よく使うrangeもありますが(start..end).toEnumeable()のほうが分かりやすいかもしれません
他にもEnumerable.repeat,Enumerable.emptyがあります
比較
機能 | LINQ(C#) | KLinq(Kotlin) |
---|---|---|
要素の取得(単一) | ||
ElementAt | elementAt | |
ElementAtOrDefault | elementAtOrDefault | |
First | first | |
FirstOrDefault | firstOrDefault | |
Last | last | |
LastOrDefault | lastOrDefault | |
Single | single | |
SingleOrDefault | singleOrDefault | |
要素の取得(複数) | ||
Where | where | |
Distinct | distinct | |
Skip | skip | |
SkipWhile | skipWhile | |
Take | take | |
TakeWhile | takeWhile | |
集計 | ||
Max | max | |
Min | min | |
Average | average | |
Sum | sum | |
Count | count | |
Aggregate | aggregate | |
判定 | ||
All | all | |
Any | any | |
Contains | contains | |
SequenceEqual | sequenceEqual | |
集合 | ||
Union | union | |
Except | except | |
Intersect | intersect | |
ソート | ||
OrderBy | orderBy | |
OrderByDescending | orderByDescending | |
ThenBy | thenBy | |
ThenByDescending | thenByDescending | |
Reverse | reverse | |
射影 | ||
Select | select | |
SelectMany | selectMany | |
GroupBy | groupBy | |
結合 | ||
Join | join | |
GroupJoin | groupJoin | |
Concat | concat | |
DefaultIfEmpty | defaultIfEmpty | |
Zip | zip | |
変換 | ||
OfType | ofType | |
Cast | cast | |
ToArray | toArray | |
ToDictionary | toDictionary | |
ToList | toList | |
ToLookup | toLookup | |
AsEnumerable | asEnumerable | |
よくやる奴 | ||
forEach |
ToDo
- ArrayかIterableに対して.toEnumeable()を呼ばなければいけない
- 関数の名前がstdlibのと衝突する場合があるので名前を変えずに実装したかったのでこの対処法になりました
- 追記)SequenceもasSequence()関数を用意してるあたりこうするしかないようですね
- KotlinにはC#のdefault(T)がないのでxxxOrDefault関数などで規定値nullになる
- TがNumberを継承しているかどうかさえ見ればなんとかなる気がしないこともないけどむりそう
- average関数でJVMだとジェネリクスのオーバーロードで衝突するのでNumberを利用
- sum関数でJVMだとジェネリクスのオーバーロードで衝突するのでNumberを利用→返り値がすべてDoubleになった
-
ofType,cast関数、いい実装方法が思いつかなかった- 追記)reifiedでそれっぽく対応
- deferredの実装がいいのだろうけど一部lazyの実装してしまった
- 関数のオーバーロードにデフォルト引数を多用したけどIntellij IDEAの補完的に普通にオーバーロードしたほうがいいかもしれない
参考
-
LINQの拡張メソッド一覧と、ほぼ全部のサンプルを作ってみました。- 地平線に行く
- 関数の並び順、LINQの挙動など参考にしました
-
IEnumerableなどのリファレンス
- 引数などの参考にしました
Author And Source
この問題について(KotlinでC#のLINQっぽいのを実装してみた), 我々は、より多くの情報をここで見つけました https://qiita.com/MeilCli/items/ee33c5c8065d79db6248著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .