LoginSignup
49
43

More than 5 years have passed since last update.

Ix.NETのススメ

Last updated at Posted at 2019-01-08

Ix.NETって何?

「Rx.NETやUniRxにあるXXXっていうメソッド(オペレーター)、なんでLINQにはないの?」って思った時におすすめなのがIx.NET。

以下、READMEより

The Interactive Extensions (Ix) is a .NET library which extends LINQ to Objects to provide many of the operators available in Rx but targeted for IEnumerable.

RxにあるオペレータをLINQ to Objectsに拡張した、つまりIEnumerable<T>で使えるようにしたのが、このライブラリです。

Ix.NETは、Rx.NETと同じリポジトリ(dotnet/reactive)に存在し、同じメンバーがメンテナンスしています。

Rxよくわかんないんだけど、使わなくていい?

Rx知らない人・使ったことがない人は、「Ix.NETはとっても便利なLINQのメソッドが、さらに増えた」と思ってください。

Ix.NETのおすすめオペレーター

わかりやすいおすすめIxのオペレーターを紹介します。

MaxByとMinBy

個人的に標準メソッド(LINQ)に入って欲しいメソッドナンバー1。

public static IList<TSource> MaxBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
public static IList<TSource> MinBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)

こんなMonsterクラスがあって、

public class Monster {
    public int Level { get; private set; } 
    /* 略 */
}

List<Monster>monstersから、一番大きいLevelを持つMonsterのオブジェクトを探したいです。

こういう時、実はLINQのMaxメソッドは使えません。

List<Monster> monsters = LoadMonsters();
int maxLevel = monsters.Max(it => it.Level);

LINQのMaxメソッドでできるのは、「monstersの要素の中の、一番大きいLevelの値を求める」こと。

ここでやりたいのは「monstersの要素の中の、一番大きいLevelの値をもつ要素を探すこと」こと。(それからもし最大値を複数の要素が持つなら、その全てを探したい。)

それができるのが、MaxBy

List<Monster> monsters = LoadMonsters();
IList<Monster> maxLevelMonsters = monsters.MaxBy(it => it.Level);

「要素の中で一番大きい評価値をもつ要素を探すこと」ことができるのがMaxBy。

逆に、

「要素の中で一番小さい評価値をもつ要素を探すこと」ことができるのがMinBy。

どちらも最大評価値・最小評価値が複数あった場合、その全てを返してくれます。

これ、本当に標準で使いたい・・・。

IsEmpty

地味だけど、便利でわかりやすいメソッド。そしてなんでLINQに標準にないんだ系のメソッド。

要素が空かどうか判別するメソッド、IsEmpty。

実装はこんな感じ。Anyを否定しているだけ。

public static bool IsEmpty<TSource>(this IEnumerable<TSource> source)
{
    if (source == null)
    {
        throw new ArgumentNullException(nameof(source));
    }

    return !source.Any();
}

あ、それからIEnumerable<T>を空か判定するときは、間違ってもCount() == 0はやっちゃいけいないよ。

Buffer

数を指定して要素をまとめるメソッド、Bufferです。

public static IEnumerable<IList<TSource>> Buffer<TSource>(this IEnumerable<TSource> source, int count)
// [[0, 1], [2, 3], [4, 5]] みたいな感じでまとめられます。
IEnumerable<IList<int>> buffered = new List<int> { 0, 1, 2, 3, 4, 5 }.Buffer(count: 2);

余った要素は、余った分だけでまとめられます。

// [[0, 1], [2, 3], [4, 5], [6]] みたいな感じでまとめられます。
IEnumerable<IList<int>> buffered = new List<int> { 0, 1, 2, 3, 4, 5, 6 }.Buffer(count: 2);

ずらす数、スキップ数を指定して、こんな感じにまとめることも。

// [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4], [4]] みたいな感じでまとめられます。
IEnumerable<IList<int>> buffered = new List<int> { 0, 1, 2, 3, 4 }.Buffer(count: 3, skip: 1);


まとめる数よりスキップ数大きくすることもできます。

// [[0, 1], [3, 4], [6, 7]] みたいな感じでまとめられます。
IEnumerable<IList<int>> buffered = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7 }.Buffer(count: 2, skip: 3);

使いどころは多くはないけど、覚えておくと便利。

あと名前付き引数呼び出しで呼び出したいメソッド。

Concat

これも地味に使いどころが多いメソッドです。他の言語だとflattenって呼ばれることもあります。

LINQにもともとあるConcatメソッドは、一つのIEnumerable<T>に他のIEnumerable<T>を連結するメソッド。

Ix.NETのConcatメソッドは、IEnumerable<IEnumerable<T>>が引数なしで呼び出すメソッド。

public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<IEnumerable<TSource>> sources)
List<List<Monster>> listOfMonsterList = LoadListOfMonsterList();
IEnumerable<<Monster> monsters = listOfMonsterList.Concat();

List<List<T>>とかArray<Array<T>>とか、IEnumerable<IList<T>>とかが呼び出せます。

地味に便利!

Repeat

LINQ標準のRepeat。「staticメソッドで、引数に渡した要素を引数の指定回数繰り返すIEnumerable<T>をつくる」ってメソッドです。実はプロダクトコードで使ったことは自分はまだありません。

一方で、Ix.NETのRepeatの各種オーバーロードは、「あー、これ使いたかったやつだ!」って自分はなりました。

// 渡した要素を何回でも繰り返すIEnumerable<T>をつくる
public static IEnumerable<TResult> Repeat<TResult>(TResult value)

// IEnumerable<T>の拡張関数で、何回でも要素を繰り返すIEnumerable<T>をつくる
public static IEnumerable<TSource> Repeat<TSource>(this IEnumerable<TSource> source)

// IEnumerable<T>の拡張関数で、指定した回数繰り返すIEnumerable<T>をつくる
public static IEnumerable<TSource> Repeat<TSource>(this IEnumerable<TSource> source, int count)

StartWith

IEnumerable<T>の拡張関数。可変長引数として渡した要素を、先頭につけてIEnumerable<T>を新たに生成。

public static IEnumerable<TSource> StartWith<TSource>(this IEnumerable<TSource> source, params TSource[] values)

TakeLastとSkipLast

TakeとSkipのLast版。

ちなみに.NET Coreでは2.0からもう標準で使えます。.NET Standard 2.1で標準にはいったので、そのうち.NET Frameworkでも使えると思います。

49
43
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
49
43