4

重なり合う範囲を折りたたむ方法のフォローアップとして、隣接する範囲を組み合わせた方法を作ろうと思いました。

基本的に、Collapseメソッドを実行した後、たとえば1から5および6から10になる可能性があります。これらを1から10の1つの範囲に結合したいと思います。

これは私がこれまでに思いついたものですが、実際にはうまく機能しません。誰かが私の問題を見つけたり、良い代替解決策を持っていますか?

    public static IEnumerable<Range<T>> MergeAdjacent<T>(this IEnumerable<Range<T>> source, Func<T, T, bool> isAdjacent)
    {
        using (var sourceIterator = source.GetEnumerator())
        {
            if (!sourceIterator.MoveNext())
                yield break;

            var first = sourceIterator.Current;

            while (sourceIterator.MoveNext())
            {
                var second = sourceIterator.Current;

                if (isAdjacent(first.End, second.Start))
                {
                    yield return Range.Create(first.Start, second.End);
                }
                else
                    yield return first;

                first = second;
            }

            yield return first;
        }
    }
4

2 に答える 2

2

この解決策にたどり着きました。前提条件の 1 つは、Func に応じて範囲が昇順または降順に並べられていることです。隣接する範囲をマージしますが、実行はまだ延期されています。私は多くのテストを実行しなかったので、これを破るエッジケースがあるかもしれません. 優しくありなさい :-)

編集:コードを少し短くしました。私が見る限り、それは機能します。nullただし、チェックを省略しました。

    public static IEnumerable<Range<T>> MergeAdjacent<T>(this IEnumerable<Range<T>> source, Func<T, T, bool> isAdjacent)
    {
        using (var it = source.GetEnumerator())
        {
            if (!it.MoveNext())
                yield break;

            var item = it.Current;

            while (it.MoveNext())
                if (isAdjacent(item.End, it.Current.Start))
                {
                    item = Range.Create(item.Start, it.Current.End);
                }
                else
                {
                    yield return item;
                    item = it.Current;
                }

            yield return item;
        }
    }

    static void Main(string[] args)
    {
        var ranges = new List<Range<int>>
        {
            Range.Create(1,3), Range.Create(4,5), Range.Create(7,10), 
            Range.Create(11,17), Range.Create(20,32), Range.Create(33,80), 
            Range.Create(90,100), 
        };

        foreach (var range in ranges.MergeAdjacent((r1, r2) => r1 + 1 == r2))
            Console.WriteLine(range);
    }

    // Result: 1-5, 7-20, 25-80, 90-100
于 2009-08-06T16:27:06.867 に答える
1

3 つ以上ではなく、隣接する 2 つの範囲のみをマージします。ギャップまたはリストの最後が見つかるまで、最後のものを保持します。

public static IEnumerable<Range<T>> MergeAdjacent<T>(this IEnumerable<Range<T>> source, Func<T, T, bool> isAdjacent)
{
    Range<T> current = null;

    foreach (Range<T> item in source)
    {
        if (current == null)
        {
            current = item;
        }
        else
        {
            if (isAdjacent(current.End, item.Start))
            {
                current = Range.Create(current.Start, item.End);
            }
            else 
            {
                yield return current;
                current = item;
            }
        }
    }

    if (current != null) 
        yield return current;
}
于 2009-08-06T15:44:27.017 に答える