Python 切片操作的 C# 等价物是什么?
my_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
result1 = my_list[2:4]
result2 = my_list[1:]
result3 = my_list[:3]
result4 = my_list[:3] + my_list[4:]
这里涵盖了其中一些,但它很丑陋并且没有解决切片的所有用途,以至于它没有明显回答问题。
如果您有
List
GetRange 可以派上用场。
来自 MSDN 链接:
引用类型集合或其子集的浅拷贝 集合,仅包含对元素的引用 收藏。对象本身不会被复制。中的参考文献 新列表指向与引用中相同的对象 原始列表。
Slice
函数可以是:
public static IEnumerable<T> Slice<T>(this List<T> source, int from, int to) => source.GetRange(from, to - from);
Python slice 支持的负范围也可以在损失一些清洁度的情况下进行处理。
这样就不用做减法了
public static IEnumerable<A> Slice<A> (int from, int to, IEnumerable<A> e) {
return e.Take (to).Skip (from);
}
这是一个扩展:
public static IEnumerable<T> Slice<T>(this IEnumerable<T> source, int start = 0, int end = 0)
{
start = (start >= 0) ? start : source.Count() + start;
end = (end > 0) ? end : source.Count() + end;
return source.Skip(start).Take(end - start);
}
示例:
var input = new[] { 0, 1, 2, 3, 4, 5, 6, 7 };
numbers.Slice(1, 4); // { 1, 2, 3 }
numbers.Slice(-3, -1); // { 5, 6 }
numbers.Slice(5); // { 5, 6, 7 }
numbers.Slice(end:-4); // { 0, 1, 2, 3 }
public static T[] slice<T>(T[] l, int from, int to)
{
T[] r = new T[to - from];
for (int i = from; i < to; i++)
{
r[i-from]=l[i];
}
return r;
}
编写自定义扩展:
public static List<T> Slice<T>(this List<T> li, int start, int end)
{
if (start < 0) // support negative indexing
{
start = li.Count + start;
}
if (end < 0) // support negative indexing
{
end = li.Count + end;
}
if (start > li.Count) // if the start value is too high
{
start = li.Count;
}
if (end > li.Count) // if the end value is too high
{
end = li.Count;
}
var count = end - start; // calculate count (number of elements)
return li.GetRange(start, count); // return a shallow copy of li of count elements
}
一些测试:
[Fact]
public void Slice_list()
{
var li1 = new List<char> {'a', 'b', 'c', 'd', 'e', 'f', 'g'};
Assert.Equal(new List<char> {'c', 'd'}, li1.Slice(2, 4));
Assert.Equal(new List<char> {'b', 'c', 'd', 'e', 'f', 'g'}, li1.Slice(1, li1.Count));
Assert.Equal(new List<char> {'a', 'b', 'c'}, li1.Slice(0, 3));
Assert.Equal(li1, li1.Slice(0, 4).Concat(li1.Slice(4, li1.Count)));
Assert.Equal(li1, li1.Slice(0, 100));
Assert.Equal(new List<char>(), li1.Slice(100, 200));
Assert.Equal(new List<char> {'g'}, li1.Slice(-1, li1.Count));
Assert.Equal(new List<char> {'f', 'g'}, li1.Slice(-2, li1.Count));
Assert.Equal(new List<char> {'a', 'b', 'c', 'd', 'e', 'f'}, li1.Slice(0, -1));
Assert.Equal(new List<char> {'c', 'd', 'e'}, li1.Slice(2, -2));
}
这是我的实现,遵循 JavaScript 的 Array.slice 方法,我相信它与 Python 实现类似:
public static IEnumerable<T> slice<T>(List<T> e, int? n1 = null, int? n2 = null)
{
if (e == null)
throw new Exception($"source must not be null");
int iFrom;
int iTo;
if (n1 == null)
{
iFrom = 0;
iTo = e.Count;
}
else if (n2 == null)
{
if (n1 < 0)
{
iFrom = e.Count + (int)n1;
if (iFrom < 0)
iFrom = 0;
iTo = e.Count;
}
else
{
iFrom = (int)n1;
iTo = e.Count;
}
}
else
{
if (n1 == null)
throw new Exception("n1 must be an integer if n2 is specified but got null");
if (n1 < 0)
throw new Exception($"n1 must be an integer >= 0 if n2 is specified but got {n1}");
iFrom = (int)n1;
iTo = (int)n2;
if (iTo < 0)
iTo = e.Count + iTo;
if (iTo <= iFrom)
iTo = iFrom;
}
return e.GetRange(iFrom, iTo - iFrom);
}
public static string[] slice(string[] source, int? n1 = null, int? n2 = null)
{
return slice(source.ToList(), n1, n2).ToArray();
}
public static object[] slice(object[] source, int? n1 = null, int? n2 = null)
{
return slice(source.ToList(), n1, n2).ToArray();
}
public static int[] slice(int[] source, int? n1 = null, int? n2 = null)
{
return slice(source.ToList(), n1, n2).ToArray();
}
上述内容适用于列表和数组(我实现了 str、int、obj)。
如果有更优雅的方式来实现Array API,请提出。我是 C# 新手。