質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

LINQ

LINQとはLanguage INtegrated Queryの略で、「統合言語クエリ」という意味です。C#やVisual Basicといった言語のコード内に記述することができるクエリです。

Q&A

解決済

3回答

2814閲覧

C#のLinqについて、メソッドチェインの途中経過を使用したい

monagano

総合スコア246

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

LINQ

LINQとはLanguage INtegrated Queryの略で、「統合言語クエリ」という意味です。C#やVisual Basicといった言語のコード内に記述することができるクエリです。

0グッド

1クリップ

投稿2017/04/05 01:20

以下の様な数値の配列を1.1倍で射影し、その最大値*0.8をボーダー値として、
ボーダー値以上の値を絞り込みたいと考えています。

{20,24,51,13,22,51,0}

C#

1int[] number_list = new int[] { 20, 24, 25, 13, 22, 25, 0 }; 2IEnumerable<double> hoge = number_list.Select(i => i * 1.1).Where(i => i >= 【Select結果】.Max() * 0.8);

下記のようにすれば実現可能なのですが、1つのメソッドチェインの中におさめてしまえないかと考え質問いたしました。

C#

1int[] number_list = new int[] { 20, 24, 25, 13, 22, 25, 0 }; 2IEnumerable<double> select_result = number_list.Select(i => i * 1.1); 3double border_number = select_result.Max(i => i ) * 0.8; 4IEnumerable<double> hoge = select_result.Where(i => i >= border_number);

初歩的な質問で申し訳ありません。
よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

こんなのは如何でしょう?

C#

1var numbers = new int[] { 20, 24, 25, 13, 22, 25, 0 } 2 .Select(i => i * 1.1) 3 .GroupBy(i => 0) 4 .Select(g => new { border = g.Max() * 0.8, g }) 5 .SelectMany(m => m.g.Where(i => i >= m.border));

投稿2017/04/05 01:42

hihijiji

総合スコア4150

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

monagano

2017/04/05 01:51

なるほど、GroupByで一旦集約させて、borderとのTupleを生成して、SelectManyで展開するのですね。 とても参考になります。 ありがとうございました!
yuba

2017/04/05 02:27

GroupByで単一グループを作る、は私も思いつきはしたのですが、やはり道具の目的外使用というのはあとから読んだときに意図を理解できなくなるんですよね。 一本のメソッドチェインに収める目的というのを考えると、記述をシンプルにしてリーダビリティを高めることだと思われるので、最終目的には反するなと思いました。
hihijiji

2017/04/05 03:09 編集

こういった GroupBy の使い方は可読性を落とすのでは?とは私も考えました。 たしかに変則的な使い方に面食らう人は多いと思います。 しかし、レスを見ると意図はちゃんと伝わっているようです。
guest

0

もし頻繁に使うのであれば、拡張メソッドを作るという手もあります。

C#

1class Program 2{ 3 public static void Main() 4 { 5 int[] number_list = new int[] { 20, 24, 25, 13, 22, 25, 0 }; 6 IEnumerable<double> hoge = number_list 7 .Select(i => i * 1.1) 8 .Where2(first => first.Max() * 0.8, (second, border) => second >= border); 9 foreach (var h in hoge) 10 { 11 Console.WriteLine(h); 12 } 13 } 14} 15 16public static class MyLinq 17{ 18 public static IEnumerable<T> Where2<T>(this IEnumerable<T> target, Func<IEnumerable<T>, T> first, Func<T, T, bool> second) 19 { 20 var arg = first(target); 21 foreach (var item in target) 22 { 23 if (second(item, arg)) yield return item; 24 } 25 } 26} 27

ところで、double の誤差で次のようになりますが、これはいいのですよね?

C#

1Console.WriteLine(20 * 1.1); 2Console.WriteLine(25 * 1.1 * 0.8); 3Console.WriteLine(20 * 1.1 >= 25 * 1.1 * 0.8);

出力

22 22 False

投稿2017/04/05 02:00

Zuishin

総合スコア28656

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

monagano

2017/04/05 02:17

ご回答ありがとうございます。 とても参考になります。 double の誤差についても、ご指摘ありがとうございます。 実コードでは日付の比較に使用するので問題ありません。
Zuishin

2017/04/05 02:30

日付の比較に使用するのであれば 22 が 22 以上にならないのはまずくないですか?
Zuishin

2017/04/05 02:44

補足します。 誤差と言いましたが、20 * 1.1 を計算していただければ、ぴったり 22 になります。そして 25 * 1.1 * 0.8 を計算すると、これもぴったり 22 になります。ところが double の内部表現の誤差の結果、まったく同じ数であるこれらが違う数として評価されます。 観測誤差がそれ以上にあるのであればこれは問題にはなりませんが、日付に定数をかけたものであれば、特定の日が含まれたり含まれなかったりするので、追試実験ができなくなります。 ということは論文に使えなくなります。 それでよろしいのでしょうか?
monagano

2017/04/05 08:29

誤解を招く文章で申し訳ありません。 ×日付の比較に使用するので問題ありません。 ○浮動小数の計算を実施しないため、問題ありません。 実際には、以下の様なコードを実装する予定です IEnumerable<Datetime> hoge = (IEnumerable<Datetime>)fuga.Where2(first => first.Max().AddMilliseconds(-500) , (second, border) => second >= border);
guest

0

var hoge = select_result.Where(i => i >= number_list.Max(n => n ) * 1.1* 0.8);

でいいのでは。
LINQは、varで受けたほうがいいと思います。

投稿2017/04/05 01:38

kiichi54321

総合スコア1984

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2017/04/05 01:54

一つのメソッドリストに収めたいということですから、select_result は使えません。 LINQ を var で受けた方がいいということもないと思います。
monagano

2017/04/05 01:59

ご回答ありがとうございます。 普段はvarで受けていますが、teratail上での見易さを考慮して型名を記載いたしました。 質問が悪く恐縮ですが、1つのメソッドチェインにおさめるのが目的でした。 回答いただいた通りborder_numberという変数を省いたとしても、2行に分割されてしまいます。 var select_result = number_list.Select(i => i * 1.1); var hoge = select_result.Where(i => i >= number_list.Max(n => n ) * 1.1* 0.8);
yuba

2017/04/05 02:30

質問では1.1倍するだけだから軽い処理なのですが、もしもっと重い処理だったら…と考えると同じフィルタ処理を繰り返さない汎用的な方法がほしくなります。 たぶん質問を出した意図もそういうことではないでしょうか。実業務のコードを出すわけにはいかないので1.1倍するという簡単な処理を例に挙げているだけで。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問