6

百万回も聞かれたと思いますが、すべての例を検索したところ、なかなか合わなかったので、とにかく聞いてみようと思いました。

私は常にそれぞれ6つのアイテムを含む2つの配列を持っています。例えば:

string[] Colors=
    new string[] { "red", "orange", "yellow", "green", "blue", "purple" };

string[] Foods=
    new string[] { "fruit", "grain", "dairy", "meat", "sweet", "vegetable" };

これらの2つの配列の間には、36の可能な組み合わせがあります(たとえば、「赤い果実」、「赤い穀物」)。

次に、これらを6つの一意の値のセットにさらにグループ化する必要があります。

例えば:

meal[0]=
    new Pair[] { 
        new Pair { One="red", Two="fruit" }, 
        new Pair { One="orange", Two="grain" }, 
        new Pair { One="yellow", Two="dairy" }, 
        new Pair { One="green", Two="meat" }, 
        new Pair { One="blue", Two="sweet" }, 
        new Pair { One="purple", Two="vegetable" } 
    };

食事はどこですか

Pair[][] meal;

「食事」のリストで要素を繰り返すことはできません。したがって、「赤」のアイテムは1つ、「肉」のアイテムは1つだけです。

最初の2つの配列に基づいてペアを簡単に作成できますが、それらを一意の組み合わせにグループ化するための最善の方法については空白を描いています。

4

3 に答える 3

5

OK、720の可能なシーケンスすべてを含むシーケンスが必要です。これは少し注意が必要ですが、実行できます。

基本的な考え方は私の前の答えと同じです。その答えでは、私たちは:

  • ランダムに順列を生成しました
  • 並べ替えられた2番目の配列を並べ替えられていない最初の配列で圧縮
  • クエリから配列を生成しました

ここで、ランダムに順列を生成する代わりに、すべての順列を生成することを除いて、同じことを行います。

このライブラリを入手することから始めます。

http://www.codeproject.com/Articles/26050/Permutations-Combinations-and-Variations-using-CG

OK、6つのアイテムのすべての順列を作成する必要があります。

Permutations<string> permutations = new Permutations<string>(foods);

それぞれの順列で何をしたいですか?私たちはすでにそれを知っています。最初にcolors配列で圧縮し、ペアのシーケンスに変換してから、配列に変換します。代わりに、それをに変えましょう。List<Pair>なぜなら、まあ、私を信じてください、それはより簡単になるからです。

IEnumerable<List<Pair>> query = 
    from permutation in permutations
    select colors.Zip(permutation, (color, food)=>new Pair(color, food)).ToList();

そして今、私たちはそのクエリを結果のリストに変えることができます。

List<List<Pair>> results = query.ToList();

これで完了です。720アイテムのリストがあります。各アイテムは、6つのペアが含まれるリストです。

明らかに、手間のかかる作業はライブラリコードによって行われます。その上に置かれるクエリは簡単です。

(LINQで順列を生成する方法について、しばらくの間ブログ記事を書くことを意味していました。これを例として使用するかもしれません!)

于 2013-02-27T01:22:38.577 に答える
4

ニーズに合わせて 720 通りの組み合わせが可能です。あなたの質問からは、720個すべてを列挙するか、ランダムに1つを選択するか、または何を選択するかが明確ではありません。私は後者を想定しています。

更新: コメントに基づくと、この仮定は正しくありませんでした。新しい回答を開始します。


まず、2 番目の配列の順列を生成します。Fischer-Yates-Knuth shuffle を使用してその場で行うことができます。StackOverflow には、その方法の例がたくさんあります。または、ランダム キーで並べ替えることで、LINQ を使用して順列を生成することもできます。

前者の手法は、項目数が多くても高速ですが、既存の配列を変更します。2 番目の手法は、特にアイテムの数が極端に多い場合は遅くなりますが、そうではありません。

2 番目の手法で犯す最も一般的な間違いは、GUID での並べ替えです。Guid は一意であることが保証されていますが、ランダムであるとは保証されていません。

とにかく、実行時に2番目の配列を並べ替えるクエリを生成します。

Random random = new Random();
IEnumerable<string> shuffled = from food in foods 
                               orderby random.NextDouble() 
                               select food;

その他の注意事項:

  • クエリ式の結果はクエリであり、結果のセットではないことに注意してください。並べ替えは、反対側で実際に配列に変換するまで発生しません。
  • 同じミリ秒内に Random の 2 つのインスタンスを作成すると、両方から同じシーケンスが得られます。
  • ランダムは疑似ランダムであり、真のランダムではありません。
  • Random はスレッドセーフではありません。

これで、並べ替えたシーケンスを最初の配列に zip 結合できます。

IEnumerable<Pair> results = colors.Zip(shuffled, (color, food)=>new Pair(color, food));

繰り返しますが、これは 2 つのシーケンスをまとめて圧縮するアクションを表すクエリです。いくつかのクエリを作成する以外は、まだ何も行われていません。

最後に配列にします。これにより、実際にクエリが実行されます。

Pair[] finalResults = results.ToArray();

簡単です。

于 2013-02-27T00:53:03.827 に答える
1

リクエストに応じて、並べ替えに関する問題の見方を具体的に説明します。C# は高水準の言語であるため、これを最小限のコードに減らすために使用できる、すばやく簡単なライブラリとオブジェクトがたくさんあることを知っています。この回答は、並べ替えロジックを実装して実際に質問を解決しようとしています。

この質問を最初に読んだとき、カードのデッキをソートすることを思い出しました。2 つの配列は、スーツの配列と額面の配列に非常に似ています。シャッフルを解決する 1 つの方法は、配列をランダム化し、両方を組み合わせたカードを選ぶことであるため、ここでも同じロジックを適用できます。

可能な解決策としての並べ替え

Fisher-Yatesソート アルゴリズムは、基本的に配列のすべてのインデックスをループ処理して、現在のインデックスをランダムなインデックスと交換します。これにより、かなり効率的な並べ替え方法が作成されます。では、これは当面の問題にどのように適用されますか? 1つの可能な実装は...

    static Random rdm = new Random();
    public string[] Shuffle(string[] c)
    {
        var random = rdm;
        for (int i = c.Length; i > 1; i--)
        {
            int iRdm = rdm.Next(i);
            string cTemp = c[iRdm];
            c[iRdm] = c[i - 1];
            c[i - 1] = cTemp;
        }
        return c;
    }

出典: Fisher-Yates Shuffle

上記のコードは、文字列配列内の値の位置をランダム化します。Colors と Food の配列をこの関数に渡すと、両方の特定のインデックスを参照することで、Pairs の一意の組み合わせを取得できます。

配列がシャッフルされるため、インデックス 0、1、2 などの 2 つの配列のペアリングは一意です。ただし、この問題では、ペアを作成する必要があります。次に、Colors と Foods の両方の特定のインデックスで値を取得する Pair クラスを作成する必要があります。つまり...色[3]と食べ物[3]

 public class Pair
{
     public string One;
     public string Two;
     public Pair(string m1, string m2)
     {
         One = m1;
         Two = m2;
     }
}

一意の組み合わせを含む配列とクラスを並べ替えたので、単純に食事配列を作成し、それにペアを設定します。

新しいペアを作成したい場合は...

Pair temp = new Pair(Colors[0],Foods[0]);

この情報を使用して、最終的に食事配列を設定できます。

    Pair[] meal = new Pair[Colors.Length - 1];
    for (int i = 0; i < Colors.Length - 1; i++)
    {
        meal[i] = new Pair(Colors[i],Foods[i]);
    } 

コードのこのセクションでは、食事配列を作成し、Colors の長さによってインデックスの数を定義します。次にコードは、新しいペア コンボを作成して食事にドロップしながら、Color 値の総数をループします。このメソッドは、配列の長さが同じであることを前提としているため、最小の配列を簡単に確認できます。

完全なコード

private void Form1_Load(object sender, EventArgs e)
        {
            string[] Colors = new string[] { "red", "orange", "yellow", "green", "blue", "purple" };
            string[] Foods = new string[] { "fruit", "grain", "dairy", "meat", "sweet", "vegetable" };
            Colors = Shuffle(Colors);
            Foods = Shuffle(Foods);
            Pair[] meal = new Pair[Colors.Length - 1];
            for (int i = 0; i < Colors.Length - 1; i++)
            {
                meal[i] = new Pair(Colors[i],Foods[i]);
            }
        }
        static Random rdm = new Random();
        public string[] Shuffle(string[] c)
        {
            var random = rdm;
            for (int i = c.Length; i > 1; i--)
            {
                int iRdm = rdm.Next(i);
                string cTemp = c[iRdm];
                c[iRdm] = c[i - 1];
                c[i - 1] = cTemp;
            }
            return c;
        }
    }
    public class Pair
    {
         public string One;
         public string Two;
         public Pair(string m1, string m2)
         {
             One = m1;
             Two = m2;
         }
     }

-元の投稿-

配列を単純にシャッフルできます。これにより、同じ方法で食事にデータを入力できますが、結果は異なります。Fisher-Yates shuffle に関する記事はこちら

于 2013-02-27T00:31:29.857 に答える