相当于 Python 切片操作的可读 C#

问题描述 投票:0回答:8

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

这里涵盖了其中一些,但它很丑陋并且没有解决切片的所有用途,以至于它没有明显回答问题。

c# python slice equivalent
8个回答
87
投票

最接近的是 LINQ

.Skip()
.Take()

示例:

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

47
投票

C#8
开始,对于索引数据结构来说,切片变得更加容易。

var result1 = myList[2..5]; // end (5) is exclusive
var result2 = myList[1..^0]; // from index 1 to the end 
var result3 = myList[0..3]; // end (3) exclusive

阅读有关范围和索引的更多信息此处此处


16
投票

如果您有

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 支持的负范围也可以在损失一些清洁度的情况下进行处理。


3
投票

这样就不用做减法了

public static IEnumerable<A> Slice<A> (int from, int to, IEnumerable<A> e) {
    return e.Take (to).Skip (from);
}

2
投票

这是一个扩展:

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 }

1
投票
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;
}

0
投票

编写自定义扩展:

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

0
投票

这是我的实现,遵循 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# 新手。

© www.soinside.com 2019 - 2024. All rights reserved.