4

現在、5分ごとに実行されるWindowsサービスがあります。このコードは、データベースから行を選択して処理します。上限(選択できる最大行数)があるため、選択される行数は0〜100の範囲で指定できます。

ランダムなパーセンテージの選択に基づいて、これらの行に対していくつかの処理を実行しようとしています。

  • タスク125%
  • タスク250%
  • タスク3100%

簡単にするために、サービスが100行を選択すると、ランダムに選択された25行がタスク1を実行し、ランダムに選択された50行がタスク2を実行し、すべての行がタスク3を実行するとします。

私が現在持っているコードは次のようになります:

var rows = repository.GetRows(100);

foreach(var row in rows)
{
    task1.Run(row);
    task2.Run(row);
    task3.Run(row);
}

これにより、すべての行で3つのタスクすべてが実行されます。各タスクに割り当てられたパーセンテージのみを選択するにはどうすればよいですか?

4

6 に答える 6

2

フィッシャー-イェーツ-ダーステンフェルトシャッフル(OrderByのNlogN時間ではなく線形時間で実行される)を実行するShuffle()拡張メソッドを定義できます。

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> input)
{
    var buffer = input.ToArray();
    //Math.Random is OK for "everyday" randomness;
    //you should use RNGCryptoServiceProvider if you need 
    //cryptographically-strong randomness
    var rng = new Math.Random();

    //as the loop proceeds, the element to output will be randomly chosen
    //from the elements at index i or above, which will then be swapped with i;
    //the yield return gives us each shuffled value as it is chosen, and
    //allows the shuffling to happen "lazily".
    for (int i = 0; i < buffer.Length; i++)
    {
        int j = rng.Next(i, buffer.Length);
        yield return buffer[j];
        //if we cared about the elements in the buffer this would be a swap,
        //but we don't, so...    
        buffer[j] = buffer[i];
    }
}

//simple extension method to provide List.ForEach()-like functionality
//on any collection or IEnumerable.
public static void ForEach(this IEnumerable<T> collection, Action<T> action)
{
    foreach(var element in collection) action(element);
}

//Usage - pretty much the same as Raphael's, 
//but now you don't have to convert to a List to use ForEach:
rows.Shuffle().Take(25).ForEach(m => task1.Run(m));
rows.Shuffle().Take(50).ForEach(m => task2.Run(m));
rows.ForEach(m => task3.Run(m));
于 2012-05-08T20:24:50.733 に答える
2

おそらく少し素朴です...

var rows = repository.GetRows(100);

rows.OrderBy(Guid.NewGuid()).Take(25).ToList().ForEach(m => task1.Run(m));
rows.OrderBy(Guid.NewGuid()).Take(50).ToList().ForEach(m => task2.Run(m));
rows.ToList().ForEach(m => task3.Run(m));
于 2012-05-08T19:54:25.443 に答える
1

この場合、ランダムサンプリング(nからm個のアイテムを選択)に対するKnuthのアプローチを使用できます。

var rows = repository.GetRows(100);
int[] maxTake = new[] {25,50,100};
int remaining = rows.Length;
Random rand = new Random();

for (int i = 0; i < rows.Length; i++)
{
    var num = rand.Next() % remaining;
    if (num < maxTake[0])
    {
        task1.Run(rows[i]);
        maxTake[0]--;
    }
    if (num < maxTake[1])
    {
        task2.Run(rows[i]);
        maxTake[1]--;
    }
    if (num < maxTake[2])
    {
        task3.Run(rows[i]);
        maxTake[2]--;
    }
    remaining--;
}
于 2012-05-08T20:06:52.217 に答える
1

次のようなランダムなサブコレクションを取得できます。

task1.Run(rows);
task2.Run(rows.OrderBy(x => Guid.NewGuid()).Take(25));
task2.Run(rows.OrderBy(x => Guid.NewGuid()).Take(50))
于 2012-05-08T19:54:28.117 に答える
0

インスタンスを使用して、Random行ごとに0.0〜1.0のランダムな値を生成できます。

行の約25%は、生成された値が0.25未満になります。また、行の約50%の生成値は0.5未満になります。

var rows = repository.GetRows(100);

Random random = new Random();

task1.Run(rows.Where(_ => random.NextDouble() <= 0.25));
task2.Run(rows.Where(_ => random.NextDouble() <= 0.5));
task3.Run(row);

行コレクションの正確に25%と50%(切り捨て)を確実に取得する場合は、次を使用します。

Random random = new Random();

var rows = repository.GetRows(100);
var rowsRandomized = rows.OrderBy(_ => random.NextDouble());

task2.Run(rowsRandomized.Take((int)(0.25 * rows.Count())));
task2.Run(rowsRandomized.Take((int)(0.5 * rows.Count())));
task3.Run(rowsRandomized);
于 2012-05-08T19:55:30.037 に答える
0

25個のランダムな一意の番号を取得する

 Random rand=new Random()

 int[] task1nums = new int[25];
 for (int i=0;i<25;i++);
 {
    int r=rand.Next(100);

    while (task1nums.Contains(r))
    {
        r=rand.Next(100);
    }
    task1nums[i]=r;
}

50個のランダムな一意の番号を取得する

 int[] task2nums = new int[50];
 for (int i=0;i<50;i++);
 {
    int r=rand.Next(100);

    while (task2nums.Contains(r))
    {
        r=rand.Next(100);
    }
    task2nums[i]=r;
}

これで、25個の乱数と50個の乱数ができました

var rows = repository.GetRows(100);
int counter=0
foreach(var row in rows)
{
    if (task1nums.Contains(counter))
    task1.Run(row);
    if (task2nums.Contains(counter))
    task2.Run(row);


    task3.Run(row);

    counter++;
} 
于 2012-05-08T19:59:58.327 に答える