1

だから、これは私が私のリストのために持っているものです。

[0], [1], [2], [3], [4]

これらをループできるようにしたいのですが、ここでの秘訣は、オフセットから開始して、そのオフセットにループバックすることです。

元。

[0], [1], [2], [3], [4]
      o-->            
//Start at offset 1 then get 2, 3, 4 then loop back around to zero

ex2。

[0], [1], [2], [3], [4]
                o-->            
//Start at offset 3 then get 4, then loop back around to zero, then 1, 2 

レギュラーを使用してList<T>この概念をforループに実装しようと考えましたが、より簡潔な方法でそれを実行したいかどうかはわかりません。

基本的に、0から開始せず、最初にループバックして、要素を経由してオフセットに戻ります。

4

2 に答える 2

7

あなたは本当にリングバッファまたは循環バッファを説明しています。

http://en.wikipedia.org/wiki/Circular_buffer

簡単な実装は

int start; // Set your desired start offset

for (int i = start; i < myList.Length; i++)
{
    // do stuff
}

for (int j = 0; j < start; j++)
{
    // do stuff
}
于 2012-09-23T22:17:48.043 に答える
0

これは、(私が思うに)すべての依存関係も含むextensionsメソッドを使用したC#の実装です。

これは、このような単純なことを投稿するための多くのコードのように思えますが、ほとんどが検証コードであり、明確に定義された動作で問題なく動作するように作成しているアプリケーションでは非常に重要でした。これらの2つの関数の上に、他にも多くのメソッドが構築されています。

このように反復することによるパフォーマンスもかなり良いように思われます。反復された値に適用される操作と比較して、ボトルネックになることはありませんでした。

SpanおよびSpanRange拡張メソッド

using System;
using System.Collections.Generic;
using Common.FluentValidation;

namespace Common.Extensions
{
    public static partial class ExtensionMethods
    {
        /// <summary>
        /// Gets the index for an array relative to an anchor point, seamlessly crossing array boundaries in either direction.
        /// Returns calculated index value of an element within a collection as if the collection was a ring of contiguous elements (Ring Buffer).
        /// </summary>
        /// <param name="p_rollover">Index value after which the iterator should return back to zero.</param>
        /// <param name="p_anchor">A fixed or variable position to offset the iteration from.</param>
        /// <param name="p_offset">A fixed or variable position to offset from the anchor.</param>
        /// <returns>calculated index value of an element within a collection as if the collection was a ring of contiguous elements (Ring Buffer).</returns>
        public static int Span(this int p_rollover, int p_anchor, int p_offset)
        {
            // Prevent absolute value of `n` from being larger than count
            int n = (p_anchor + p_offset) % p_rollover;

            // If `n` is negative, then result is n less than rollover
            if (n < 0)
                n = n + p_rollover;

            return n;
        }

        /// <summary>
        /// Iterates over a collection from a specified start position to an inclusive end position. Iterator always increments
        /// from start to end, treating the original collection as a contiguous ring of items to be projected into a new form.
        /// Returns a projected collection of items that can contain all of the items from the original collection or a subset of the items.
        /// The first item in the projected collection will be the item from the original collection at index position p_first.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="p_collection">The collection to project into a new form.</param>
        /// <param name="p_first">Zero based index value of the first element in the projected sequence.</param>
        /// <param name="p_last">Zero based index value of the last element in the projected sequence.</param>
        /// <returns>a projected collection of items that can contain all of the items from the original collection or a subset of the items.
        /// The first item in the projected collection will be the item from the original collection at index position p_first.</returns>
        public static IEnumerable<T> SpanRange<T>(this IList<T> p_collection, int p_first, int p_last)
        {
            // Validate
            p_collection
                .CannotBeNullOrEmpty("p_collection");
            p_first
                .MustBeWithinRange(0, p_collection.Count - 1, "p_first");
            p_last
                .MustBeWithinRange(0, p_collection.Count - 1, "p_last");

            // Init
            int Rollover = p_collection.Count;
            int Count = (p_first <= p_last) ? p_last - p_first : (Rollover - p_first) + p_last;

            // Iterate
            for (int i = 0; i <= Count; i++)
            {
                var n = Rollover.Span(p_first, i);
                yield return p_collection[n];
            }
        }
    }
}

CouldBeNullOrEmpty依存関係

using System;
using System.Collections.Generic;
using System.Linq;

namespace Common.FluentValidation
{
    public static partial class Validate
    {
        /// <summary>
        /// Validates the passed in parameter is not null or an empty collection, throwing a detailed exception message if the test fails.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="p_parameter">Parameter to validate.</param>
        /// <param name="p_name">Name of tested parameter to assist with debugging.</param>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public static void CannotBeNullOrEmpty<T>(this ICollection<T> p_parameter, string p_name)
        {
            if (p_parameter == null)
                throw
                    new
                        ArgumentNullException(string.Format(
                        "The collection \"{0}\" cannot be null.",
                        p_name), default(Exception));

            if (p_parameter.Count <= 0)
                throw
                    new
                        ArgumentOutOfRangeException(string.Format(
                        "The collection \"{0}\" cannot be empty.",
                        p_name), default(Exception));
        }

        /// <summary>
        /// Validates the passed in parameter is not null or an empty collection, throwing a detailed exception message if the test fails.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="p_parameter">Parameter to validate.</param>
        /// <param name="p_name">Name of tested parameter to assist with debugging.</param>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public static void CannotBeNullOrEmpty<T>(this IEnumerable<T> p_parameter, string p_name)
        {
            if (p_parameter == null)
                throw
                    new
                        ArgumentNullException(string.Format(
                        "The collection \"{0}\" cannot be null.",
                        p_name), default(Exception));

            if (p_parameter.Count() <= 0)
                throw
                    new
                        ArgumentOutOfRangeException(string.Format(
                        "The collection \"{0}\" cannot be empty.",
                        p_name), default(Exception));
        }

        /// <summary>
        /// Validates the passed in parameter is not null or empty, throwing a detailed exception message if the test fails.
        /// </summary>
        /// <param name="p_parameter">Parameter to validate.</param>
        /// <param name="p_name">Name of tested parameter to assist with debugging.</param>
        /// <exception cref="ArgumentException"></exception>
        public static void CannotBeNullOrEmpty(this string p_parameter, string p_name)
        {
            if (string.IsNullOrEmpty(p_parameter))
                throw
                    new
                        ArgumentException(string.Format(
                        "The string \"{0}\" cannot be null or empty.",
                        p_name), default(Exception));
        }
    }
}

MustBeWithinRangeの依存関係

using System;

namespace Common.FluentValidation
{
    public static partial class Validate
    {
        /// <summary>
        /// Validates the passed in parameter is within a specified range of values, throwing a detailed exception message if the test fails.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="p_parameter">Parameter to validate.</param>
        /// <param name="p_minInclusive">The minimum valid value of the parameter.</param>
        /// <param name="p_maxInclusive">The maximum valid value of the parameter.</param>
        /// <param name="p_name">Name of tested parameter to assist with debugging.</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public static void MustBeWithinRange<T>(this IComparable<T> p_parameter, T p_minInclusive, T p_maxInclusive, string p_name)
            where T : struct
        {
            if (p_parameter.CompareTo(p_minInclusive) == -1)
                throw
                    new
                        ArgumentOutOfRangeException(string.Format(
                        "Parameter cannot be less than {0}, but \"{1}\" was {2}.",
                        p_minInclusive, p_name, p_parameter), default(Exception));

            if (p_parameter.CompareTo(p_maxInclusive) == 1)
                throw
                    new
                        ArgumentOutOfRangeException(string.Format(
                        "Parameter cannot be greater than {0}, but \"{1}\" was {2}.",
                        p_maxInclusive, p_name, p_parameter), default(Exception));
        }
    }
}

注:ユニットテストの依存関係を含めるにはコードが多すぎるため、独自の同様の拡張メソッドがある場合、またはPrint()すべての値をダンプするだけのステートメントのようなものをコメントアウトするだけで、テストケース名の冗長性がポイントを理解できることを願っていますセミインテリジェントな方法でStringBuilderに変換します。NuGetから利用できるFluentValidationが必要になるか、... Should()。Be(...)を標準のAssert(...)メソッドに置き換えるだけです。

ユニットテストスパン(NUnitフレームワーク)

using System;
using System.Text;
using Common.Extensions;
using Common.FluentValidation;
using FluentAssertions;
using NUnit.Framework;

namespace UnitTests.CommonTests.Extensions
{
    [TestFixture, Timeout(1000)]
    public class Span_Tests
    {
        // Test Anchoring
        [Test]
        public void Span_10_anchored_at_0_with_no_offset_should_be_0_Tests()
        {
            10.Span(0, 0).Should().Be(0);
        }

        [Test]
        public void Span_10_anchored_at_1_with_no_offset_should_be_1_Tests()
        {
            10.Span(1, 0).Should().Be(1);
        }

        [Test]
        public void Span_10_anchored_at_negative_1_with_no_offset_should_be_9_Tests()
        {
            10.Span(-1, 0).Should().Be(9);
        }

        [Test]
        public void Span_10_anchored_at_negative_10_with_no_offset_should_be_0_Tests()
        {
            10.Span(-10, 0).Should().Be(0);
        }

        // Test Offset
        [Test]
        public void Span_10_anchored_at_0_with_offset_of_1_should_be_1_Tests()
        {
            10.Span(0, 1).Should().Be(1);
        }

        [Test]
        public void Span_10_anchored_at_0_with_offset_of_negative_1_should_be_9_Tests()
        {
            10.Span(0, -1).Should().Be(9);
        }

        [Test]
        public void Span_10_anchored_at_0_with_offset_of_negative_10_should_be_0_Tests()
        {
            10.Span(0, -10).Should().Be(0);
        }

        // Test Iterations
        [Test]
        public void Span_array_of_10_anchored_at_0_can_walk_forward_thru_elements_twice_Tests()
        {
            var sb = new StringBuilder();

            try
            {
                var SequentialData = new int[10];
                for (int i = 0; i < SequentialData.Length; i++)
                    SequentialData[i] = i;

                sb.AppendFormat("SequentialData:\r\n{0}", SequentialData.Print());

                for (int i = 0; i < 20; i++)
                {
                    var n = SequentialData.Length.Span(0, i);

                    SequentialData[n].Should().Be(i % 10);
                }
            }
            catch (Exception)
            {
                Console.WriteLine(sb.ToString());
                throw;
            }
        }

        [Test]
        public void Span_array_of_10_anchored_at_0_can_walk_backwards_thru_elements_twice_Tests()
        {
            var sb = new StringBuilder();

            try
            {
                var SequentialData = new int[10];
                for (int i = 0; i < SequentialData.Length; i++)
                    SequentialData[i] = i;

                sb.AppendFormat("SequentialData:\r\n{0}", SequentialData.Print());

                for (int i = 0; i > -20; i--)
                {
                    var n = SequentialData.Length.Span(0, i);
                    var j = (i % 10);

                    switch (j)
                    {
                        case 0: SequentialData[n].Should().Be(0); break;
                        case -1: SequentialData[n].Should().Be(9); break;
                        case -2: SequentialData[n].Should().Be(8); break;
                        case -3: SequentialData[n].Should().Be(7); break;
                        case -4: SequentialData[n].Should().Be(6); break;
                        case -5: SequentialData[n].Should().Be(5); break;
                        case -6: SequentialData[n].Should().Be(4); break;
                        case -7: SequentialData[n].Should().Be(3); break;
                        case -8: SequentialData[n].Should().Be(2); break;
                        case -9: SequentialData[n].Should().Be(1); break;

                        default:
                            throw
                                j.ToString().CannotBeSwitchedToDefault("j");
                    }
                }
            }
            catch (Exception)
            {
                Console.WriteLine(sb.ToString());
                throw;
            }
        }
    }
}

ユニットテストSpanRange(NUnitフレームワーク)

using System;
using System.Collections.Generic;
using System.Text;
using Common.Extensions;
using FluentAssertions;
using NUnit.Framework;

namespace UnitTests.CommonTests.Extensions
{
    [TestFixture, Timeout(1000)]
    public class SpanRange_Tests
    {
        [Test]
        public void SpanRange_array_of_10_from_0_to_9_should_be_0_thru_9_Tests()
        {
            var sb = new StringBuilder();

            try
            {
                var Expected = new List<int>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

                var SequentialData = new int[10];
                for (int i = 0; i < SequentialData.Length; i++)
                    SequentialData[i] = i;

                sb.AppendFormat("SequentialData:\r\n{0}", SequentialData.Print());
                sb.AppendLine();

                var Range = new List<int>(SequentialData.SpanRange(0, 9));

                sb.AppendFormat("Range:\r\n{0}", Range.Print());

                Range.ShouldBeEquivalentTo(Expected);
            }
            catch (Exception)
            {
                Console.WriteLine(sb.ToString());
                throw;
            }
        }

        [Test]
        public void SpanRange_array_of_10_from_0_to_9_should_not_throw_ArgumentOutOfRangeException_Tests()
        {
            foreach (var item in new int[10].SpanRange(0, 9))
            { }
        }

        [Test, ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SpanRange_array_of_10_from_0_to_10_should_throw_ArgumentOutOfRangeException_Tests()
        {
            foreach (var item in new int[10].SpanRange(0, 10))
            { }
        }

        [Test, ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SpanRange_array_of_10_from_negative_1_to_9_should_throw_ArgumentOutOfRangeException_Tests()
        {
            foreach (var item in new int[10].SpanRange(-1, 9))
            { }
        }

        [Test]
        public void SpanRange_array_of_10_from_1_to_0_should_be_1_thru_9_then_0_Tests()
        {
            var sb = new StringBuilder();

            try
            {
                var Expected = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };

                var SequentialData = new int[10];
                for (int i = 0; i < SequentialData.Length; i++)
                    SequentialData[i] = i;

                sb.AppendFormat("SequentialData:\r\n{0}", SequentialData.Print());
                sb.AppendLine();

                var Range = new List<int>(SequentialData.SpanRange(1, 0));

                sb.AppendFormat("Range:\r\n{0}", Range.Print());

                Range.ShouldBeEquivalentTo(Expected);
            }
            catch (Exception)
            {
                Console.WriteLine(sb.ToString());
                throw;
            }
        }

        [Test]
        public void SpanRange_array_of_10_from_1_to_3_should_be_1_thru_3_Tests()
        {
            var sb = new StringBuilder();

            try
            {
                var Expected = new List<int>() { 1, 2, 3 };

                var SequentialData = new int[10];
                for (int i = 0; i < SequentialData.Length; i++)
                    SequentialData[i] = i;

                sb.AppendFormat("SequentialData:\r\n{0}", SequentialData.Print());
                sb.AppendLine();

                var Range = new List<int>(SequentialData.SpanRange(1, 3));

                sb.AppendFormat("Range:\r\n{0}", Range.Print());

                Range.ShouldBeEquivalentTo(Expected);
            }
            catch (Exception)
            {
                Console.WriteLine(sb.ToString());
                throw;
            }
        }

        [Test]
        public void SpanRange_array_of_10_from_9_to_1_should_be_9_0_and_1_Tests()
        {
            var sb = new StringBuilder();

            try
            {
                var Expected = new List<int>() { 9, 0, 1 };

                var SequentialData = new int[10];
                for (int i = 0; i < SequentialData.Length; i++)
                    SequentialData[i] = i;

                sb.AppendFormat("SequentialData:\r\n{0}", SequentialData.Print());
                sb.AppendLine();

                var Range = new List<int>(SequentialData.SpanRange(9, 1));

                sb.AppendFormat("Range:\r\n{0}", Range.Print());

                Range.ShouldBeEquivalentTo(Expected);
            }
            catch (Exception)
            {
                Console.WriteLine(sb.ToString());
                throw;
            }
        }

        [Test]
        public void SpanRange_array_of_5_from_1_to_4_should_be_1_thru_4_Tests()
        {
            var sb = new StringBuilder();

            try
            {
                var Expected = new List<int>() { 1, 2, 3, 4 };

                var SequentialData = new int[5];
                for (int i = 0; i < SequentialData.Length; i++)
                    SequentialData[i] = i;

                sb.AppendFormat("SequentialData:\r\n{0}", SequentialData.Print());
                sb.AppendLine();

                var Range = new List<int>(SequentialData.SpanRange(1, 4));

                sb.AppendFormat("Range:\r\n{0}", Range.Print());

                Range.ShouldBeEquivalentTo(Expected);
            }
            catch (Exception)
            {
                Console.WriteLine(sb.ToString());
                throw;
            }
        }

        [Test]
        public void SpanRange_array_of_5_from_0_to_0_should_be_0_Tests()
        {
            var sb = new StringBuilder();

            try
            {
                var Expected = new List<int>() { 0 };

                var SequentialData = new int[5];
                for (int i = 0; i < SequentialData.Length; i++)
                    SequentialData[i] = i;

                sb.AppendFormat("SequentialData:\r\n{0}", SequentialData.Print());
                sb.AppendLine();

                var Range = new List<int>(SequentialData.SpanRange(0, 0));

                sb.AppendFormat("Range:\r\n{0}", Range.Print());

                Range.ShouldBeEquivalentTo(Expected);
            }
            catch (Exception)
            {
                Console.WriteLine(sb.ToString());
                throw;
            }
        }

        [Test]
        public void SpanRange_array_of_5_from_1_to_1_should_be_1_Tests()
        {
            var sb = new StringBuilder();

            try
            {
                var Expected = new List<int>() { 1 };

                var SequentialData = new int[5];
                for (int i = 0; i < SequentialData.Length; i++)
                    SequentialData[i] = i;

                sb.AppendFormat("SequentialData:\r\n{0}", SequentialData.Print());
                sb.AppendLine();

                var Range = new List<int>(SequentialData.SpanRange(1, 1));

                sb.AppendFormat("Range:\r\n{0}", Range.Print());

                Range.ShouldBeEquivalentTo(Expected);
            }
            catch (Exception)
            {
                Console.WriteLine(sb.ToString());
                throw;
            }
        }

        [Test]
        public void SpanRange_array_of_5_from_4_to_0_should_be_4_then_0_Tests()
        {
            var sb = new StringBuilder();

            try
            {
                var Expected = new List<int>() { 4, 0 };

                var SequentialData = new int[5];
                for (int i = 0; i < SequentialData.Length; i++)
                    SequentialData[i] = i;

                sb.AppendFormat("SequentialData:\r\n{0}", SequentialData.Print());
                sb.AppendLine();

                var Range = new List<int>(SequentialData.SpanRange(4, 0));

                sb.AppendFormat("Range:\r\n{0}", Range.Print());

                Range.ShouldBeEquivalentTo(Expected);
            }
            catch (Exception)
            {
                Console.WriteLine(sb.ToString());
                throw;
            }
        }

        [Test]
        public void SpanRange_array_of_5_from_1_to_0_should_be_1_thru_4_then_0_Tests()
        {
            var sb = new StringBuilder();

            try
            {
                var Expected = new List<int>() { 1, 2, 3, 4, 0 };

                var SequentialData = new int[5];
                for (int i = 0; i < SequentialData.Length; i++)
                    SequentialData[i] = i;

                sb.AppendFormat("SequentialData:\r\n{0}", SequentialData.Print());
                sb.AppendLine();

                var Range = new List<int>(SequentialData.SpanRange(1, 0));

                sb.AppendFormat("Range:\r\n{0}", Range.Print());

                Range.ShouldBeEquivalentTo(Expected);
            }
            catch (Exception)
            {
                Console.WriteLine(sb.ToString());
                throw;
            }
        }
    }
}
于 2014-03-31T16:44:12.937 に答える