要素の配列があり、それぞれに開始時刻と終了時刻があります。
これらはタイムラインを形成し、一部は重複し、一部は重複しません(重複する要素のグループ間にギャップがあります)。
重複しない要素間のギャップ(下の画像のように赤い線)を削除するコードをいくつか記述しましたが、乱雑になり始め、Edgeのケースをキャッチできなくなりました。
赤いギャップを取り除き、すべてをきれいにシフトするアルゴリズムはすでに存在しますか?
私のコードスタブは以下です:
// sort by time, lowest to highest
entries.Sort((a, b) => a.TimeOffset.CompareTo(b.TimeOffset));
var lookingForFirstGap = true;
var storedOffset = 0.0;
var indexToTrimFrom = 0;
for (var i = 0; i < entries.Count -1; i++ )
{
// var previous = entries[i-1];
var current = entries[i];
var next = entries[i+1];
// var distanceBack = previous.TimingsAbsolute.End - current.TimingsAbsolute.Start;
var distanceForward = next.TimingsAbsolute.Start - current.TimingsAbsolute.End;
Console.WriteLine("Distance {0} -> {1} is {2}", i, i+1, distanceForward);
if (!(distanceForward > 0))
continue;
if (lookingForFirstGap)
{
indexToTrimFrom = i + 1;
Console.WriteLine("To trim from " + indexToTrimFrom);
storedOffset = distanceForward; // we have found a gap, store the amount
lookingForFirstGap = false; // now start looking for element where there is a gap after it
}
else
{
var indexToTrimTo = i;
for (var x = indexToTrimFrom; x <= indexToTrimTo; x++)
{
// trim all
Console.WriteLine("Adjust [" + x + "] by " + storedOffset);
}
if (distanceForward > 0)
{
indexToTrimFrom = i + 1;
Console.WriteLine("To trim from " + indexToTrimFrom);
storedOffset = distanceForward; // we have found a gap, store the amount
}
else
lookingForFirstGap = true; // start looking for gap again
}
}
1つのループでやりすぎている。ギャップを特定することは難しいため、ギャップを差し引くことは困難です。間隔がオーバーラップするすべての奇妙な方法のため、ギャップを特定することは困難です。したがって、最初にオーバーラップする間隔の問題を削除します。
この質問 のアルゴリズムを使用して、1つのパスを作成して間隔を平坦化します。次に、1つのパスでギャップのリストを作成します。これは、フラット化されたリストを使用すると非常に簡単になるはずです。
これで間隔の元のリストをループする準備が整いました。各間隔について、その前に発生するギャップの数を確認し、それぞれの累積時間を差し引きます。
これをコードとして投稿することで、@ Karlはこれを分割することで簡単になったことを実感できました。 SOLID原則により、コードがはるかに簡単になります。
List<Tuple<int, int>> FindGaps(List<LogEntry> entries)
{
var gaps = new List<Tuple<int, int>>();
for (var i = 0; i < entries.Count - 1; i++)
{
var current = entries[i];
var next = entries[i + 1];
var distanceForward = next.TimingsAbsolute.Start - current.TimingsAbsolute.End;
if (!(distanceForward > 0)) // there is no gap to the next element, continue
continue;
gaps.Add(new Tuple<int, int>(i, i+1)); // otherwise, we have found a gap...
}
return gaps;
}
List<Tuple<int, int>> FindContiguous(List<Tuple<int, int>> gaps, int totalLength)
{
var previous = 0;
var lastIndex = totalLength - 1;
var contiguous = new List<Tuple<int, int>>();
foreach (var gap in gaps)
{
contiguous.Add(new Tuple<int, int>(previous,gap.Item1));
previous = gap.Item2;
}
if (previous != lastIndex)
{
contiguous.Add(new Tuple<int, int>(previous,lastIndex));
}
return contiguous;
}
List<LogEntry> RemoveGaps(List<LogEntry> entries, List<Tuple<int, int>> contiguous)
{
var newList = new List<LogEntry>();
var totalShift = 0.0;
LogEntry previousLast = null;
foreach (var seq in contiguous)
{
var startIndex = seq.Item1;
var endIndex = seq.Item2;
if (previousLast != null)
{
totalShift += entries[startIndex].TimingsAbsolute.Start - previousLast.TimingsAbsolute.End;
}
previousLast = entries[endIndex];
for (var i = startIndex; i <= endIndex; i++)
{
var entry = entries[i];
newList.Add(
new LogEntry(
entry.Url,
entry.Status,
entry.HeaderSize,
entry.PayloadSize,
entry.TimeOffset-totalShift,
entry.Timings.Blocked,
entry.Timings.Dns,
entry.Timings.Connect,
entry.Timings.Ssl,
entry.Timings.Send,
entry.Timings.Wait,
entry.Timings.Receive,
entry.ConnectionId));
}
}
return newList;
}
public void Generate(List<LogEntry> entries, Guid testId)
{
// sort by time, lowest to highest
entries.Sort((a, b) => a.TimeOffset.CompareTo(b.TimeOffset));
// get a list of contigous elements
var contiguous = FindContiguous(FindGaps(entries), entries.Count);
// now remove the gaps between the contiguous sequences of elements
var list = RemoveGaps(entries, contiguous);
}