这是一个编译和工作的实现,尽管它仍然有些粗糙。它要求输入状态数组正确考虑整个感兴趣的时间范围(结束 - 开始),但是添加一些代码会使最终状态填满第一个 N 中未考虑的时间将是微不足道的-1 州。我还修改了您的结构定义以在持续时间中使用整数而不是长整数,只是为了简化一点。
为清楚起见(和懒惰),我省略了所有错误检查。它适用于您所描述的输入,但它绝不是防弹的。
public static Interval[] GetRandomIntervals( DateTime start, DateTime end,
StateSummary[] states, int totalIntervals )
{
Random r = new Random();
// stores the number of intervals to generate for each state
int[] intervalCounts = new int[states.Length];
int intervalsTemp = totalIntervals;
// assign at least one interval for each of the states
for( int i = 0; i < states.Length; i++ )
intervalCounts[i] = 1;
intervalsTemp -= states.Length;
// assign remaining intervals randomly to the various states
while( intervalsTemp > 0 )
{
int iState = r.Next( states.Length );
intervalCounts[iState] += 1;
intervalsTemp -= 1;
}
// make a scratch copy of the state array
StateSummary[] statesTemp = (StateSummary[])states.Clone();
List<Interval> result = new List<Interval>();
DateTime next = start;
while( result.Count < totalIntervals )
{
// figure out which state this interval will go in (this could
// be made more efficient, but it works just fine)
int iState = r.Next( states.Length );
if( intervalCounts[iState] < 1 )
continue;
intervalCounts[iState] -= 1;
// determine how long the interval should be
int length;
if( intervalCounts[iState] == 0 )
{
// last one for this state, use up all remaining time
length = statesTemp[iState].TotalSeconds;
}
else
{
// use up at least one second of the remaining time, but
// leave some time for the remaining intervals
int maxLength = statesTemp[iState].TotalSeconds -
intervalCounts[iState];
length = r.Next( 1, maxLength + 1 );
}
// keep track of how much time is left to assign for this state
statesTemp[iState].TotalSeconds -= length;
// add a new interval
Interval interval = new Interval();
interval.State = states[iState].State;
interval.Date = next;
interval.Duration = length;
result.Add( interval );
// update the start time for the next interval
next += new TimeSpan( 0, 0, length );
}
return result.ToArray();
}