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

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

ただいまの
回答率

90.50%

  • C#

    7121questions

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

  • LINQ

    109questions

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

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

解決済

回答 3

投稿

  • 評価
  • クリップ 1
  • VIEW 724

monagano

score 234

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

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

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

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

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

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+3

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/04/05 10:51

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

    キャンセル

  • 2017/04/05 11:27

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

    キャンセル

  • 2017/04/05 11:51 編集

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

    キャンセル

+1

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

class Program
{
    public static void Main()
    {
        int[] number_list = new int[] { 20, 24, 25, 13, 22, 25, 0 };
        IEnumerable<double> hoge = number_list
            .Select(i => i * 1.1)
            .Where2(first => first.Max() * 0.8, (second, border) => second >= border);        
        foreach (var h in hoge)
        {
            Console.WriteLine(h);
        }
    }
}

public static class MyLinq
{
    public static IEnumerable<T> Where2<T>(this IEnumerable<T> target, Func<IEnumerable<T>, T> first, Func<T, T, bool> second)
    {
        var arg = first(target);
        foreach (var item in target)
        {
            if (second(item, arg)) yield return item;
        }
    }
}

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

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

出力

22
22
False

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/04/05 11:17

    ご回答ありがとうございます。
    とても参考になります。

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

    キャンセル

  • 2017/04/05 11:30

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

    キャンセル

  • 2017/04/05 11:44

    補足します。

    誤差と言いましたが、20 * 1.1 を計算していただければ、ぴったり 22 になります。そして 25 * 1.1 * 0.8 を計算すると、これもぴったり 22 になります。ところが double の内部表現の誤差の結果、まったく同じ数であるこれらが違う数として評価されます。

    観測誤差がそれ以上にあるのであればこれは問題にはなりませんが、日付に定数をかけたものであれば、特定の日が含まれたり含まれなかったりするので、追試実験ができなくなります。
    ということは論文に使えなくなります。
    それでよろしいのでしょうか?

    キャンセル

  • 2017/04/05 17:29

    誤解を招く文章で申し訳ありません。
    ×日付の比較に使用するので問題ありません。
    ○浮動小数の計算を実施しないため、問題ありません。

    実際には、以下の様なコードを実装する予定です
    IEnumerable<Datetime> hoge = (IEnumerable<Datetime>)fuga.Where2(first => first.Max().AddMilliseconds(-500) , (second, border) => second >= border);

    キャンセル

0

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/04/05 10:54

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

    キャンセル

  • 2017/04/05 10: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);

    キャンセル

  • 2017/04/05 11:30

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

    キャンセル

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

  • ただいまの回答率 90.50%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C#

    7121questions

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

  • LINQ

    109questions

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