In python, I can take a list my_list and rotate the contents:
>>> my_list = list(range(10))
>>> my_list
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>
var newlist = oldlist.Skip(1).Concat(oldlist.Take(1));
You can easily use LINQ to do this:
// Create the list
int[] 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:
public static IEnumerable<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:
public static IEnumerable<T> Slice<T>(this IEnumerable<T> source, int count)
{
// If the enumeration is null, throw an exception.
if (source == null) throw new ArgumentNullException("source");
// Validate count.
if (count < 0) throw new 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 is IList<T>)
{
// Return the list slice.
return SliceList ((IList<T>) source);
}
// Slice everything else.
return SliceEverything(source, count);
}
private static IEnumerable<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.
yield return arr[index];
}
// Get the items at the beginning.
for (int index = 0; index < count; index++)
{
// Return the items from the beginning.
yield return arr[index];
}
}
private static IEnumerable<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.
yield return list[index];
}
// Get the items at the beginning.
for (int index = 0; index < list.Count; index++)
{
// Return the items from the beginning.
yield return list[index];
}
}
// Helps with storing the sliced items.
internal class SliceHelper<T> : IEnumerable<T>
{
// Creates a
internal SliceHelper(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.
private int 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()
{
throw new 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.
yield return item;
}
}
}
}
private static IEnumerable<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);
}
Function
/*
list : the list that is to be rotated
shift : the number of elements to be shifted
direction : direction of shift (1 -> left, -1 -> right)/default left
*/
public List<T> Rotate<T>(List<T> list, int shift, int direction = 1)
{
int j = 0;
List<T> temp_buffer = new List<T>();
if(direction == -1)
{
shift = list.Count - shift;
}
for (int i = 0; i < list.Count; i++)
{
if (i < shift)
{
temp_buffer.Add(list[i]);
}
if (i < list.Count - shift)
{
list[i] = list[i + shift];
}
else
{
list[i] = temp_buffer[j];
j++;
}
}
return list;
}
Usage Example
List<int> list = new List<int>() {1, 2, 3, 4, 5, 6, 7, 8, 9};
int shift = 4; //enter the number of elements to be shifted
//printing the list before rotating
Console.Write("Before\t: ");
for(int i = 0; i< list.Count; i++)
{
Console.Write(list[i] + " ");
}
list = Rotate<int>(list, shift, -1);
//printing the list after rotating
Console.Write("\nAfter \t: ");
for(int i = 0; i< list.Count; i++)
{
Console.Write(list[i] + " ");
}
List<int> list1;
List<int> list2 = new List<int>(list1);
or you can
list2.AddRange(list1);
To get a distinct list using LINQ
List<int> distinceList = list2.Distinct<int>().ToList<int>();
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>
public static IEnumerable<T> Slice<T>(this T[] array,
int? start = null, int? end = null, int step = 1)
{
array.NullArgumentCheck("array");
// step
if (step == 0)
{
// handle gracefully
yield break;
}
// step > 0
int _start = 0;
int _end = array.Length;
// step < 0
if (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;
};
// start
if (_start < -array.Length || _start >= array.Length)
{
yield break;
}
_start = toPositiveIndex(_start, array.Length);
// end
if (_end < -array.Length - 1)
{
yield break;
}
if (_end > array.Length)
{
_end = array.Length;
}
_end = toPositiveIndex(_end, array.Length);
// slice
if (step > 0)
{
// start, end
if (_start > _end)
{
yield break;
}
for (int i = _start; i < _end; i += step)
{
yield return array[i];
}
}
else
{
// start, end
if (_end > _start)
{
yield break;
}
for (int i = _start; i > _end; i += step)
{
yield return 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)]
public void Slice01(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());
}
}
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.