きままにブログ

プログラミングを主とした私のメモ帳です。寂しいのでコメントください笑

LINQ for C++ライブラリを使ってみた

ヘッダファイル1つインクルードするだけで使えるこのライブラリは、簡単に使えてちょっとした配列の操作にもいいかもしれないですね。

#include <stdio.h>
#include <LINQ/cpplinq.hpp>

int main() {
	using namespace cpplinq;

	struct student {
		char* name;
		int point;
	} list[] = {
		{ "A", 30 },
		{ "B", 50 },
		{ "C", 60 },
		{ "D", 70 },
	};

	auto result = from_array(list)
		>> where([](student s) { return s.point >= 60; })
		>> to_vector();

	printf("合格者\n");
	for(auto& it : result) {
		printf("%s : %d\n", it.name, it.point);
	}

	getchar();
	return 0;
}

並び替えてみよう

他のコードは殆ど同じなので一部省略しています。

auto result = from_array(list)
	>> where([](student s) { return s.point >= 60; })
	>> orderby_ascending([](student s) { return s.point; })
	>> to_vector();

for(auto& it : result) {
	printf("%s : %d\n", it.name, it.point);
}

同じ点だったらID(学籍番号的なもの)について並び替えてみよう

int main() {
	using namespace cpplinq;

	struct student {
		char* name;
		int point;
		int id;
	} list[] = {
		{ "A", 66, 1 },
		{ "B", 66, 2 },
		{ "C", 58, 3 },
		{ "D", 66, 4 },
		{ "E", 74, 5 },
	};

	auto result = from_array(list)
		>> orderby_ascending([](student s) { return s.point; })
		>> thenby_ascending([](student s) { return -s.id; })
		>> to_vector();

	for(auto& it : result) {
		printf("%s : %d\n", it.name, it.point);
	}

	getchar();
	return 0;
}

1から100整数の内、奇数のものだけの合計

auto result = range(1, 100)
	>> where([](int n) { return n % 2 == 1; })
	>> sum();

printf("%d", result);

計算

count, sum, max, min, avg。sumと使い方は同じです。

skip, take

最初の10個の要素を飛ばして、その後10個の要素だけ対象に、ある条件の要素をだけを集める。

auto result = range(1, 100)
	>> skip(10)
	>> take(10)
	>> where([](int n) { return n % 2 == 0; })
	>> to_vector();

for(auto it : result) {
	printf("%d\n", it);
}

take_while, skip_whileもあって、これはある条件の間の要素を撮ったりスキップしたり出来る。

同じものを繰り返し並べる

repeat(同じもの, 繰り返し数)で可能。

要素を生成する

to_optはOptional型のようなもので、何も引数を与えなければnullptrのような扱い、引数を与えればそのものというふうな型です。generateでは、逐次引数の関数が実行され、to_opt(~)で値を作成しつづけ、to_opt()を返して終了とします。ただし、型を与えないといけません。

int x = 5;
using T = tuple < int, int > ;
auto result = generate(
	[x]() mutable {
		--x;
		return x <= 0 ? to_opt<T>() : to_opt(T(x, 5 - x));
})
	>> to_vector();

for(auto& it : result) {
	printf("(%d, %d)\n", get<0>(it), get<1>(it));
}

結果は、

(4, 1)
(3, 2)
(2, 3)
(1, 4)

すべての要素に適用

例えば、range(1, 10)で1から10までの数を作って、それを2倍して、2から20までの数を作る例 :

auto result = range(1, 10)
	>> select([](int n) { return n * 2; })
	>> to_vector();

for(auto it : result) {
	printf("%d\n", it);
}

重複する要素

int a[] = { 0, 1 };

auto result = range(1, 10)
	>> select([](int n) { return n % 3; })
	>> intersect_with(from_array(a))
	>> to_vector();

for(auto it : result) {
	printf("%d\n", it);
}

重複しない要素

int a[] = { 0, 1 };

auto result = range(1, 10)
	>> select([](int n) { return n % 3; })
	>> except(from_array(a))
	>> to_vector();

for(auto it : result) {
	printf("%d\n", it);
}

特定の要素を基準としてみる

#include <stdio.h>
#include <tuple>
#include <LINQ/cpplinq.hpp>

int main() {
	using namespace cpplinq;
	using std::tuple;
	using std::get;

	auto lookup = range(1, 10)
		>> select([](int n) { return std::make_tuple(n, n % 3); })
		>> to_lookup([](tuple<int, int> t) { return get<1>(t); });

	auto result = lookup[1]
		>> where([](tuple<int, int> t) { return get<0>(t) % 2 == 0; })
		>> select([](tuple<int, int> t) { return get<0>(t); })
		>> to_vector();

	for(auto& it : result) {
		printf("%d\n", it);
	}

	getchar();
	return 0;
}

まず、selectで10個の整数からtupleで、(実際の数, 3で割ったあまりの数)を作ります。次に、to_lookupであまりの数に着目します。そして、lookup[1]で余りが1のものだけを抽出し、その中で実際の数が偶数のものだけを抜き取ります。この場合は結局、3で割った余りが1の偶数を抜き出したことになります。

すべての要素が等しいか判定

auto is_equal = range(1, 10)
	>> sequence_equal(range(1, 10));
printf("%d", is_equal);

最初の要素を取得

条件を与えることも、与えないことも出来ます。取得できないと例外cpplinq::sequence_empty_exceptionが投げられます。

auto result = range(1, 10)
	>> first([](int n) { return n % 2 == 0; });

printf("%d", result);

同じキー列の2つのデータ列をまとめる

struct Data {
	char* name;
	int point;
	int id;
};

Data data_a[] = {
	{ "A", 33, 1 },
	{ "B", 44, 2 },
	{ "C", 55, 3 },
	{ "D", 66, 4 },
};

Data data_b[] = {
	{ "A", 77, 1 },
	{ "E", 20, 5 },
	{ "F", 30, 6 },
	{ "B", 40, 2 }
};

auto result = from_array(data_a)
	>> join(
	from_array(data_b),
	[](Data d) { return d.id; },
	[](Data d) { return d.id; },
	[](Data da, Data db) { return std::make_tuple(da.name, da.point, db.point); })
	>> to_vector();

for(auto& it : result) {
	printf("(%s, %d, %d)\n", get<0>(it), get<1>(it), get<2>(it));
}

とすると

(A, 33, 77)
(B, 44, 40)

と返って来ます。つまり、data_a, data_b2つのデータのうち共通のIDであり、それらをtupleで結合したデータを出力しているのですね。

~が 少なくとも1つ, すべて, 含まれる

int a[] = { 3, 5, 8, 9 };

printf("%d\n", from_array(a)
	>> any([](int n) { return n > 5; })); // true
printf("%d\n", from_array(a)
	>> all([](int n) { return n > 5; })); // false
printf("%d\n", from_array(a)
	>> contains(5)); // true