@mu-MueLangDeveloper

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

while文をLINQ to Objectsに書き換えたい

Discussion

Closed

解決したいこと

 タイトルの通りwhile文をLINQ to Objectsで書き換えたい。
 一応、while文をLINQ to Objectsで書き換えたあことはあるが、繰り返す条件に左右されずに書き換える方法が思い浮かばなかったので、何か方法があれば教えて欲しい。

LINQで実装したことのあるwhile文の条件

 以下はその条件
 変数はいくつでもあって良いが、それらを定数など制限のかけられているものに使わなければならない(例えば、配列、IEnumerable<T>を実装しているもの)。

全ての条件で実装可能にするには

 「全ての条件」まで拡張するには可変のものに対応させなければならない。

0 likes

while文をLINQ to Objectsで書き換えたあことはあるが

質問者さんが書いたものの中からサンプルとして適当なものを挙げて、

繰り返す条件に左右されずに書き換える

というのがどういうことかそのサンプルをベースに説明することはできますか?

2Like

@SurferOnWww
 LINQ to Objectsで書き換えたものとしては、並びのわからない配列の中の任意の値のインデックスを条件付きで取り出すコードです。
普通に書いたとき

using System;
using System.Linq;

class Program
{
    static void Main()
    {
        int[] array = new int[]{1, 2, 3, 4}; // 並びのわからない配列
                                             // ここでは[1, 2, 3, 4]とする
        int findValue = 2; // 2を探す
        int index = 0;
        // 2の倍数であり、2が格納されている配列の要素のインデックスを見つけて、出力する
        if (!array.Contains(findValue)) index = -1;
        else while (array[index] % 2 != 0 || array[index] != findValue) index++;
        Console.WriteLine(index);
    }
}

LINQ to Objectsで書き直したやつ

using System;
using System.Linq;

class Program
{
    static void Main()
    {
        int[] array = new int[]{1, 2, 3, 4}; // 並びのわからない配列
                                             // ここでは[1, 2, 3, 4]とする
        int findValue = 2; // 2を探す
        // LINQ to Objectsの拡張メソッドのほぼ全ては値を返すため、switch式を利用する
        int index = array.Contains(findValue) switch { true => array.Zip(array.Select((_, i) => i)).First(x => x.First % 2 == 0 && x.First == findValue).Second, false => -1 };
        Console.WriteLine(index);
    }
}

こうすれば、時間のかかる可能性のある繰り返しを使わなくて良い。
しかし、クイックソートを実装したとき

using System;

class Program {
    public static void Main(string[] args) {
        Console.WriteLine(string.Join(", ", QuickSort([15, 1, 19, 21, 8, 15])));
    }
    private static int[] QuickSort(int[] arr, int left = 0, int right = -1) {
        right = right == -1 ? arr.Length - 1 : right;
        int i = left;
        int j = right;
        int pivot = arr[left];

        while (i <= j) {
            while (arr[i] < pivot) i++;
            while (arr[j] > pivot) j--;
            if (i <= j) {
                int v = arr[i];
                arr[i] = arr[j];
                arr[j] = v;
                i++;
                j--;
            }
        }
        if (left < j) QuickSort(arr, left, j);
        if (i < right) QuickSort(arr, i, right);
        return arr;
    }
}

QuickSortメソッドを一行で実装しようとしたとき、int.TryParse()で最初の変数宣言まではできたもののwhile文の条件式i <= jという条件のもと、それをLINQ to Objectsまたはそれ以外のメソッドで実装することができませんでした。
 「条件に左右されずに書き換える」というのは、条件が不等式であってもwhile文をLINQ to Objectsで書き換えることです。さらに言うと、不等式の左辺と右辺が可変の変数のときでも書き換えられるようにする。(等式でも同じことが言える)

0Like

私には、提示いただいた例題を while や Linq to Objects を使って解決するという発想が出てこないです。

なので「while文をLINQ to Objectsに書き換え」については案が出てきません。せっかく例題を提示いただいたのにすみませんが、他の方の回答をお待ちください。

結局は、適材適所とか、組織のコーディングルールとか、後は個人の好みの問題とかで考える話になるのではと思います。

ちなみに、個人の好みで書かせていただけると、以下のようになります。

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            int[] array = new int[] { 1, 2, 3, 4 }; 
            int findValue = 2;
            int index = -1;
            // 自分にとって一目でわかるように書くのが好みです
            for (int i = 0; i < array.Length; i++)
            {
                if (array[i] % 2 == 0 && array[i] == findValue)
                {
                    index = i;
                    break;
                }
            }
            Console.WriteLine(index);

            Console.WriteLine("--------------------------------");

            // .NET のライブラリ List<T>.Sort メソッドを使うのが良さそう
            int[] array2 = new int[] { 15, 1, 19, 21, 8, 15 };
            var list = array2.ToList();
            list.Sort();
            foreach(int value in list)
            {
                Console.WriteLine(value);
            }
        }
    }
}

結果は:

result.jpg

0Like

@SurferOnWww
想像しただけで、合ってるかどうかは試していませんが、

static int[] QuickSort(int[] arr, int left = 0, int right = -1) => new int[] { arr[(left is int i ? 0 : 0)..][(right == -1 ? arr.Length - 1 : right is int j ? 0 : 0)..][(arr[left] is int pivot ? 0 : 0)..][(new Func<string, int[]>(s => 0) is Func<string, int[]> func ? 0 : 0)..][((func = new Func<string, int[]>(s => func(i <= j ? (int.TryParse(s, out int _) switch { false => [0], true => (i = arr.Zip(arr.Select((_, i) => i)).Last(t => t.First < pivot).Second + 1) <= (j = arr.Zip(arr.Select((_, i) => i)).First(t => t.First > pivot).Second - 1) ? arr = [.. arr.Select((x, k) => k == i ? arr[j--] : (k == j ? arr[i++] : x))] : [0] }).Sum().ToString() : ((int.TryParse(s, out int _) switch { false => [0], true => (i = arr.Zip(arr.Select((_, i) => i)).Last(t => t.First < pivot).Second + 1) <= (j = arr.Zip(arr.Select((_, i) => i)).First(t => t.First > pivot).Second - 1) ? arr = [.. arr.Select((x, k) => k == i ? arr[j--] : (k == j ? arr[i++] : x))] : [0] }).Sum().ToString() is strin ? : "" : ""))))(""))..] }.Select(x => func("0")).ToArray()[(left < j ? ((arr = QuickSort(arr, left, j)).Sum() is int ? 0 : 0) : 0)..][(i < right ? ((arr = QuickSort(arr, i, right)).Sum() is int ? 0 : 0) : 0)..][0];

で、できるのではと考えています。

0Like

コードは読みやすいようインデントしてください。

あなたの想像の話ではなくて、そのコードで解決したい課題は何かの詳細と、コードを実行しての結果、課題は解決できたのかを書いてください。

0Like

Your answer might help someone💌