Как рассчитать общее количество секунд многих перекрывающихся дат и времени

Вы не даете достаточно подробностей. Поскольку ваше первое выражение работает, я предполагаю, что вы используете режим Singleline.

Следующее мое предположение состоит в том, что эта строка является частью большей строки.

^ соответствует начало строки по умолчанию

$ по умолчанию соответствует концу строки.

Теперь, поскольку ваша строка содержит материал до и после, вам нужно изменить это поведение по умолчанию:

С модификатором Multiline, ^ соответствует началу строки, а $ - концу строки. Дополнительную информацию см. В документации .

Итак, ваше регулярное выражение должно выглядеть примерно так:

Regex regx = new Regex("(?<=^(\s*Owner))(.|\n)*?(?=\s*Information$)", RegexOptions.Singleline | RegexOptions.Multiline);

3
задан Nedo Alaimo 16 January 2019 в 18:15
поделиться

3 ответа

Одним из способов сделать это было бы расширение вашего класса дополнительным методом, который объединит список TimeLapse объектов, взяв все перекрывающиеся и объединив их в один TimeLapse, а затем вернув этот набор. Если мы сделаем это, то мы можем просто сложить продолжительность каждого элемента в наборе. Вы также можете добавить свойство, которое предоставляет Duration объекта TimeLapse:

private class TimeLapse
{
    public DateTime StartTime { get; set; }
    public DateTime EndTime { get; set; }
    public TimeSpan Duration => (EndTime - StartTime).Duration();

    public static List<TimeLapse> Merge(List<TimeLapse> items)
    {
        if (items == null || items.Count < 2) return items;

        var results = new List<TimeLapse>();

        foreach (var item in items)
        {
            var overlappingItem = results.FirstOrDefault(item.OverlapsWith);
            if (overlappingItem == null) results.Add(item);
            else overlappingItem.CombineWith(item);
        }

        return results;
    }

    private bool OverlapsWith(TimeLapse other)
    {
        return other != null &&
               other.StartTime <= EndTime &&
               other.EndTime >= StartTime;
    }

    private void CombineWith(TimeLapse other)
    {
        if (!OverlapsWith(other)) return;
        if (other.StartTime < StartTime) StartTime = other.StartTime;
        if (other.EndTime > EndTime) EndTime = other.EndTime;
    }
}

Ниже приведен пример того, как вы можете отображать длительности для каждого элемента в вашем словаре.

Я включил метод для создания фиктивного списка устройств, поэтому я использую Days, потому что его было проще писать и проверять правильность результатов, но поскольку Duration является [118 ], вы можете получить практически любую единицу измерения (например, TotalSeconds в вашем случае):

private static void Main()
{
    Dictionary<string, List<TimeLapse>> devices = GetDeviceList();

    foreach (var device in devices)
    {
        Console.WriteLine("{0}: {1} total days", device.Key,
            TimeLapse.Merge(device.Value).Sum(value => value.Duration.TotalDays));
    }

    GetKeyFromUser("Done! Press any key to exit...");
}

private static Dictionary<string, List<TimeLapse>> GetDeviceList()
{
    return new Dictionary<string, List<TimeLapse>>
    {
        // device1 total should be 4 days (1/1 - 1/5)
        {"device1", new List<TimeLapse>{
            new TimeLapse {StartTime = DateTime.Parse("1/1/2019"),
                EndTime = DateTime.Parse("1/3/2019")},
            new TimeLapse {StartTime = DateTime.Parse("1/2/2019"),
                EndTime = DateTime.Parse("1/3/2019")},
            new TimeLapse {StartTime = DateTime.Parse("1/3/2019"),
                EndTime = DateTime.Parse("1/5/2019")}}},

        // device2 total should be 7 days (1/1 - 1/4 plus 1/6 - 1/10)
        {"device2", new List<TimeLapse>{
            new TimeLapse {StartTime = DateTime.Parse("1/1/2019"),
                EndTime = DateTime.Parse("1/3/2019")},
            new TimeLapse {StartTime = DateTime.Parse("1/3/2019"),
                EndTime = DateTime.Parse("1/4/2019")},
            new TimeLapse {StartTime = DateTime.Parse("1/6/2019"),
                EndTime = DateTime.Parse("1/10/2019")}}},

        // device3 total should be 2 days (1/1 - 1/2 plus 1/6 - 1/7)
        {"device3", new List<TimeLapse>{
            new TimeLapse {StartTime = DateTime.Parse("1/1/2019"),
                EndTime = DateTime.Parse("1/2/2019")},
            new TimeLapse {StartTime = DateTime.Parse("1/6/2019"),
                EndTime = DateTime.Parse("1/7/2019")}}},

        // device4 total should be 2 days (1/1 - 1/3)
        {"device4", new List<TimeLapse>{
            new TimeLapse {StartTime = DateTime.Parse("1/1/2019"),
                EndTime = DateTime.Parse("1/3/2019")}}},
    };
}

Вывод

[1111 ] enter image description here

0
ответ дан Rufus L 16 January 2019 в 18:15
поделиться

Демонстрация красоты LINQ путем написания метода расширения.

/// <summary>
/// Gets the duration of the set union of the specified intervals.
/// </summary>
/// <param name="timeLapses">Sequence of <see cref="TimeLapse"/> ordered by <see cref="TimeLapse.StartTime"/>.</param>
public static TimeSpan UnionDurations(this IEnumerable<TimeLapse> timeLapses)
{
    using (var e = timeLapses.GetEnumerator())
    {
        if (!e.MoveNext()) // no items, no duration
            return TimeSpan.Zero;

        var prev = e.Current;
        var total = prev.EndTime - prev.StartTime; // set running total to duration of 1st interval

        while (e.MoveNext())
        {
            var curr = e.Current;
            if (curr.StartTime < prev.StartTime) throw new Exception($"{nameof(timeLapses)} are not in ascending {nameof(TimeLapse.StartTime)} order.");

            var increase = curr.EndTime - (curr.StartTime > prev.EndTime ? curr.StartTime : prev.EndTime);
            if (increase <= TimeSpan.Zero) continue;
            total += increase;
            prev = curr;
        }

        return total;
    }
}

Тестовый код:

var input = new Dictionary<string, IList<TimeLapse>>
{
    {
        "A",
        new[]
        {
            new TimeLapse{ StartTime = new DateTime(2019, 1, 17, 0, 0, 0), EndTime = new DateTime(2019, 1, 17, 3, 0, 0)},
            new TimeLapse{ StartTime = new DateTime(2019, 1, 17, 1, 0, 0), EndTime = new DateTime(2019, 1, 17, 2, 0, 0)},
            new TimeLapse{ StartTime = new DateTime(2019, 1, 17, 1, 0, 0), EndTime = new DateTime(2019, 1, 17, 4, 0, 0)},
            new TimeLapse{ StartTime = new DateTime(2019, 1, 17, 5, 0, 0), EndTime = new DateTime(2019, 1, 17, 7, 0, 0)}
        }
    },
    {
        "B",
        new TimeLapse [0]
    }
};
var result = input
    .Select(kv => new
    {
        Device = kv.Key,
        FaultyDuration = kv.Value
            // .OrderBy(tl => tl.StartTime) // this line can be removed if already ordered by StartTime
            .UnionDurations()
    })
    .ToList();
// { Device = A, FaultyDuration = 06:00:00 }
// { Device = B, FaultyDuration = 00:00:00 }
0
ответ дан tinudu 16 January 2019 в 18:15
поделиться

Я не уверен, что вы бы назвали «отвратительным», но если вы просто хотите, чтобы количество секунд для каждого промежутка времени было, вы могли бы создать метод для вашего класса TimeLapse, который возвращает именно это.

private class TimeLapse
{
    public DateTime StartTime { get; set; }
    public DateTime EndTime { get; set; }

    public double GetSecondsPassed() {
        return (EndTime - StartTime).TotalSeconds
    }
}

Разница между двумя объектами DateTime возвращает объект TimeSpan . И вместо того, чтобы иметь словарь ваших объектов TimeLapse, вы можете иметь словарь двойных значений (который представляет секунды) .

var _devices = new Dictionary<string, double>()
0
ответ дан izzy255 16 January 2019 в 18:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: