在python中,我可以列出my_list列表并旋转内容:
>>> my_list = list(range(10))
>>> my_list
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> new_list = my_list[1:] + my_list[:1]
>>> new_list
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
在C#中创建一个由两个现有C#列表组成的新列表的等效方法是什么?我知道如果有必要,我可以通过蛮力生成。
答案 0 :(得分:41)
var newlist = oldlist.Skip(1).Concat(oldlist.Take(1));
答案 1 :(得分:18)
您可以轻松使用LINQ执行此操作:
// 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));
您甚至可以将其添加为扩展方法,如下所示:
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));
}
当然,上面需要进行一些错误检查,但这是一般的前提。
考虑到这一点,可以对该算法进行明确的改进,从而提高性能。
如果IEnumerable<T>
实例实现IList<T>
或者是一个数组,那么你肯定可以利用它被索引的事实。
此外,您可以减少在消息正文中跳过和占用所需的迭代次数。
例如,如果您有200个项目并且想要切片值为199,那么它需要199(对于初始跳过)+ 1(对于剩余项目)+ 199(对于采取)迭代Slice方法的主体。这可以通过迭代列表一次来减少,将项目存储在列表中,然后将列表连接到自身(不需要迭代)。
在这种情况下,这里的权衡是记忆。
为此,我为扩展方法提出以下建议:
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);
}
答案 2 :(得分:9)
C#中最接近的是使用Enumerable.Skip和Enumerable.Take扩展方法。您可以使用它们来构建新列表。
答案 3 :(得分:1)
List<int> list1;
List<int> list2 = new List<int>(list1);
或者你可以
list2.AddRange(list1);
使用LINQ获取不同的列表
List<int> distinceList = list2.Distinct<int>().ToList<int>();
答案 4 :(得分:1)
要旋转数组,请执行a.Slice(1, null).Concat(a.Slice(null, 1))
。
这是我对它的刺痛。 a.Slice(step: -1)
提供了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测试:
[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());
}
}
答案 5 :(得分:0)
功能
double &GetX()
{
static double x = 400;
return x;
}
// We are accessing x here to modify y
// Then we are modifying x itself
// Pass x by reference
double &AccessAndChangeX(double& x)
{
static double y;
y = x + 12; // We are accessing x here and using to modify y.
// Let's modify x
x = 100;
return y;
}
void PrintXY(double x, double y)
{
std::cout << x;
std::cout << y;
}
int main()
{
double &x = GetX(); // Take the initial value of x. 400.
double &y = AccessAndChangeX(x);
//Print initial value of x and value of y(generated using x)
PrintXY(x, y);
// X was modified while AccessAndChangeX(x). Check if x was changed!
std::cout << "\n" << "What is the value of x now : " << GetX();
}
用法示例
/*
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;
}