可读的C#等价于Python切片操作

可读的C#等价于Python切片操作,c#,python,slice,equivalent,C#,Python,Slice,Equivalent,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:] ,但它很难看,并且没有解决切片的所有用途,以至于它没有明显地回答这个问题。最接近的是LINQ and 例如: var result1 = myList.Skip

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:]

,但它很难看,并且没有解决切片的所有用途,以至于它没有明显地回答这个问题。

最接近的是LINQ and

例如:

var result1 = myList.Skip(2).Take(2);
var result2 = myList.Skip(1);
var result3 = myList.Take(3);
var result4 = myList.Take(3).Concat(myList.Skip(4));

这样你就不用减法了

public static IEnumerable<A> Slice<A> (int from, int to, IEnumerable<A> e) {
    return e.Take (to).Skip (from);
}
公共静态IEnumerable切片(int-from、int-to、IEnumerable e){
返回e.带(到)。跳过(从);
}
公共静态T[]片(T[]l,int-from,int-to)
{
T[]r=新的T[to-from];
for(int i=from;i
如果你有一个
列表
可以派上用场

从MSDN链接:

引用类型集合或其子集的浅层副本 集合,仅包含对 收集对象本身不会被复制。中的参考文献 新列表指向与中的引用相同的对象 原始列表

切片
功能可以是:

public static IEnumerable<T> Slice<T>(this List<T> source, int from, int to) => source.GetRange(from, to - from);
公共静态IEnumerable切片(此列表源、int-from、int-to)=>source.GetRange(from、to-from);

python slice支持的负数范围也可以在一定程度上减少清洁度。

编写一个自定义扩展:

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
}
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);
}
公共静态列表切片(此列表li,int start,int end)
{
if(start<0)//支持负索引
{
开始=li.计数+开始;
}
if(end<0)//支持负索引
{
end=li.Count+end;
}
if(start>li.Count)//如果开始值太高
{
start=li.Count;
}
if(end>li.Count)//如果end值太高
{
结束=li.计数;
}
var count=end-start;//计算计数(元素数)
return li.GetRange(start,count);//返回count元素的li的浅拷贝
}
一些测试:

[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));
}
[事实]
公共无效切片列表()
{
var li1=新列表{'a','b','c','d','e','f','g'};
相等(新列表{'c','d'},li1.Slice(2,4));
相等(新列表{'b','c','d','e','f','g'},li1.Slice(1,li1.Count));
相等(新列表{'a','b','c'},li1.Slice(0,3));
Assert.Equal(li1,li1.Slice(0,4.Concat)(li1.Slice(4,li1.Count));
等于(li1,li1.Slice(01100));
等于(newlist(),li1.Slice(100200));
等于(新列表{'g'},li1.Slice(-1,li1.Count));
相等(新列表{'f',g'},li1.Slice(-2,li1.Count));
相等(新列表{'a','b','c','d','e','f'},li1.Slice(0,-1));
相等(新列表{'c','d','e'},li1.Slice(2,-2));
}
C#8
开始,对于索引数据结构,切片变得容易得多

阅读更多关于范围和索引的信息。

这里有一个扩展:

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
}
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);
}

+1当我抓取MSDN URL时,你比我抢到了更棘手的例子:-)这一个是你的。我可以建议使用
result1
result2
来匹配OP的示例吗?我希望我可以使用Python(工作项目),但我想我必须满足于这种丑陋的东西,在阅读它时我实际上必须思考。虽然答案很有帮助,但示例除了第二行之外是完全错误的。我建议进行编辑。此解决方案不完整,因为它不支持负索引(例如,[-5:-4])。LINQ
SklpLast
TakeLast
方法模拟负索引。在回答中添加说明它支持负索引吗?Python有。不,take显然大于0,如果你看一下他的描述,也可以跳过。您可以传递负数而不产生任何异常。我实际上在ArraySlice中实现了Python类型切片。请检查:
List
不使用
Range
实现索引,范围模式需要名为
Slice
的成员,遗憾的是不支持扩展方法。
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 }