Help us understand the problem. What is going on with this article?

Ix.NETのススメ

More than 1 year has passed since last update.

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はやっちゃいけいないよ。

https://qiita.com/RyotaMurohoshi/items/6f90a08f354032b6030d

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でも使えると思います。

RyotaMurohoshi
プログラミングが大好きで、 C#が大好きで、 .NETが大好きで、 LINQが大好きで、 JVM言語が大好きで、 ゲームで遊ぶことが大好きで、 ゲーム開発が大好きで、 頑張るのが大好きで、 Unityが大好きだったから...!
http://mrstar-memo.hatenablog.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした