C# Equivalent Of Rotating A List Using Python Slice Operation
Solution 1:
var newlist = oldlist.Skip(1).Concat(oldlist.Take(1));
Solution 2:
You can easily use LINQ to do this:
// Create the listint[] my_list = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
IEnumerable<int> new_list =
my_list.Skip(1).Concat(my_list.Take(1));
You could even add this as an extension method like so:
publicstaticIEnumerable<T> Slice<T>(this IEnumerable<T> e, int count)
{
// Skip the first number of elements, and then take that same number of// elements from the beginning.return e.Skip(count).Concat(e.Take(count));
}
Of course there needs to be some error checking in the above, but that's the general premise.
Thinking about this more, there are definite improvements that can be made to this algorithm which would improve performance.
You can definitely take advantage if the IEnumerable<T>
instance implements IList<T>
or is an array, taking advantage of the fact that it is indexed.
Also, you can cut down on the number of iterations that are required to skip and take would take within the body of the message.
For example, if you have 200 items and you want to slice with a value of 199, then it requires 199 (for the initial skip) + 1 (for the remaining item) + 199 (for the take) iterations in the body of the Slice method. This can be cut down by iterating through the list once, storing the items in a list which is then concatenated to itself (requiring no iteration).
In this case, the trade off here is memory.
To that end, I propose the following for the extension method:
publicstaticIEnumerable<T> Slice<T>(this IEnumerable<T> source, int count)
{
// If the enumeration is null, throw an exception.if (source == null) thrownew ArgumentNullException("source");
// Validate count.if (count < 0) thrownew ArgumentOutOfRangeException("count",
"The count property must be a non-negative number.");
// Short circuit, if the count is 0, just return the enumeration.if (count == 0) return source;
// Is this an array? If so, then take advantage of the fact it// is index based.if (source.GetType().IsArray)
{
// Return the array slice.return SliceArray((T[]) source, count);
}
// Check to see if it is a list.if (source isIList<T>)
{
// Return the list slice.return SliceList ((IList<T>) source);
}
// Slice everything else.return SliceEverything(source, count);
}
privatestaticIEnumerable<T> SliceArray<T>(T[] arr, int count)
{
// Error checking has been done, but use diagnostics or code// contract checking here.
Debug.Assert(arr != null);
Debug.Assert(count > 0);
// Return from the count to the end of the array.for (int index = count; index < arr.Length; index++)
{
// Return the items at the end.yieldreturn arr[index];
}
// Get the items at the beginning.for (int index = 0; index < count; index++)
{
// Return the items from the beginning.yieldreturn arr[index];
}
}
privatestaticIEnumerable<T> SliceList<T>(IList<T> list, int count)
{
// Error checking has been done, but use diagnostics or code// contract checking here.
Debug.Assert(list != null);
Debug.Assert(count > 0);
// Return from the count to the end of the list.for (int index = count; index < list.Count; index++)
{
// Return the items at the end.yieldreturn list[index];
}
// Get the items at the beginning.for (int index = 0; index < list.Count; index++)
{
// Return the items from the beginning.yieldreturn list[index];
}
}
// Helps with storing the sliced items.internalclassSliceHelper<T> : IEnumerable<T>
{
// Creates ainternalSliceHelper(IEnumerable<T> source, int count)
{
// Test assertions.
Debug.Assert(source != null);
Debug.Assert(count > 0);
// Set up the backing store for the list of items// that are skipped.
skippedItems = new List<T>(count);
// Set the count and the source.this.count = count;
this.source = source;
}
// The source.
IEnumerable<T> source;
// The count of items to slice.privateint count;
// The list of items that were skipped.private IList<T> skippedItems;
// Expose the accessor for the skipped items.public IEnumerable<T> SkippedItems { get { return skippedItems; } }
// Needed to implement IEnumerable<T>.// This is not supported.
System.Collections.IEnumerator
System.Collections.IEnumerable.GetEnumerator()
{
thrownew InvalidOperationException(
"This operation is not supported.");
}
// Skips the items, but stores what is skipped in a list// which has capacity already set.public IEnumerator<T> GetEnumerator()
{
// The number of skipped items. Set to the count.int skipped = count;
// Cycle through the items.foreach (T item in source)
{
// If there are items left, store.if (skipped > 0)
{
// Store the item.
skippedItems.Add(item);
// Subtract one.
skipped--;
}
else
{
// Yield the item.yieldreturn item;
}
}
}
}
privatestaticIEnumerable<T> SliceEverything<T>(this IEnumerable<T> source, int count)
{
// Test assertions.
Debug.Assert(source != null);
Debug.Assert(count > 0);
// Create the helper.
SliceHelper<T> helper = new SliceHelper<T>(
source, count);
// Return the helper concatenated with the skipped// items.return helper.Concat(helper.SkippedItems);
}
Solution 3:
The closest thing in C# would be to use the Enumerable.Skip and Enumerable.Take extension methods. You could use these to build your new list.
Solution 4:
List<int> list1;
List<int> list2 = newList<int>(list1);
or you can
list2.AddRange(list1);
To get a distinct list using LINQ
List<int> distinceList = list2.Distinct<int>().ToList<int>();
Solution 5:
To rotate array, do a.Slice(1, null).Concat(a.Slice(null, 1))
.
Here's my stab at it. a.Slice(step: -1)
gives a reversed copy as a[::-1]
.
///<summary>/// Slice an array as Python.///</summary>///<typeparam name="T"></typeparam>///<param name="array"></param>///<param name="start">start index.</param>///<param name="end">end index.</param>///<param name="step">step</param>///<returns></returns>///<remarks>/// http://docs.python.org/2/tutorial/introduction.html#strings/// +---+---+---+---+---+/// | H | e | l | p | A |/// +---+---+---+---+---+/// 0 1 2 3 4 5/// -6 -5 -4 -3 -2 -1 ///</remarks>publicstaticIEnumerable<T> Slice<T>(this T[] array,
int? start = null, int? end = null, int step = 1)
{
array.NullArgumentCheck("array");
// stepif (step == 0)
{
// handle gracefullyyieldbreak;
}
// step > 0int _start = 0;
int _end = array.Length;
// step < 0if (step < 0)
{
_start = -1;
_end = -array.Length - 1;
}
// inputs
_start = start ?? _start;
_end = end ?? _end;
// get positive index for given index
Func<int, int, int> toPositiveIndex = (int index, int length) =>
{
return index >= 0 ? index : index + length;
};
// startif (_start < -array.Length || _start >= array.Length)
{
yieldbreak;
}
_start = toPositiveIndex(_start, array.Length);
// endif (_end < -array.Length - 1)
{
yieldbreak;
}
if (_end > array.Length)
{
_end = array.Length;
}
_end = toPositiveIndex(_end, array.Length);
// sliceif (step > 0)
{
// start, endif (_start > _end)
{
yieldbreak;
}
for (int i = _start; i < _end; i += step)
{
yieldreturn array[i];
}
}
else
{
// start, endif (_end > _start)
{
yieldbreak;
}
for (int i = _start; i > _end; i += step)
{
yieldreturn array[i];
}
}
}
nunit tests:
[Test]
// normal cases
[TestCase(3, 5, 1, 3, 4)]
[TestCase(0, 5, 1, 0, 4)]
[TestCase(3, null, 1, 3, 9)]
[TestCase(0, null, 1, 0, 9)]
[TestCase(null, null, 1, 0, 9)]
[TestCase(0, 10, 1, 0, 9)]
[TestCase(0, int.MaxValue, 1, 0, 9)]
[TestCase(-1, null, 1, 9, 9)]
[TestCase(-2, null, 1, 8, 9)]
[TestCase(0, -2, 1, 0, 7)]
// corner cases
[TestCase(0, 0, 1, null, null)]
[TestCase(3, 5, 2, 3, 3)]
[TestCase(3, 6, 2, 3, 5)]
[TestCase(100, int.MaxValue, 1, null, null)]
[TestCase(int.MaxValue, 1, 1, null, null)]
[TestCase(-11, int.MaxValue, 1, null, null)]
[TestCase(-6, -5, 1, 4, 4)]
[TestCase(-5, -6, 1, null, null)]
[TestCase(-5, -5, 1, null, null)]
[TestCase(0, -10, 1, null, null)]
[TestCase(0, -11, 1, null, null)]
[TestCase(null, null, 100, 0, 0)]
// -ve step
[TestCase(null, null, -1, 9, 0)]
[TestCase(-7, -5, -1, null, null)]
[TestCase(-5, -7, -1, 5, 4)]
[TestCase(-5, -7, -2, 5, 5)]
[TestCase(-7, null, -1, 3, 0)]
publicvoidSlice01(int? s, int? e, int i, int? first, int? last)
{
var a = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var slice = a.Slice(start: s, end: e, step: i).ToArray();
Print(slice);
if (first.HasValue)
{
Assert.AreEqual(first, slice.First());
}
if (last.HasValue)
{
Assert.AreEqual(last, slice.Last());
}
}
Post a Comment for "C# Equivalent Of Rotating A List Using Python Slice Operation"