【问题标题】:Readable C# equivalent of Python slice operationPython slice 操作的可读 C# 等价物
【发布时间】:2014-01-07 20:12:18
【问题描述】:

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

Some of it is covered here,但它很丑,并没有解决切片的所有用途,以至于它没有明显回答问题。

【问题讨论】:

标签: c# python slice equivalent


【解决方案1】:

最接近的真的是 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));

【讨论】:

  • +1 在我抓取 MSDN URL 时,你击败了我,获得了更棘手的示例 :-) 这个是你的。我可以建议使用result1result2 来匹配 OP 的示例吗?
  • 我希望我可以使用 Python(工作项目),但我想我将不得不接受这些丑陋的东西,我在阅读它时实际上必须考虑它。
  • 虽然答案很有帮助,但除了第 2 行之外,示例完全错误。我提出了修改建议。
  • 此解决方案不完整,因为它不支持负索引(例如 [-5:-4])。
  • LINQ SklpLastTakeLast 方法模仿负索引。
【解决方案2】:

这样就不用减了

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

【讨论】:

  • 是否支持负索引? Python 可以。
  • 不,显然是> 0,如果您看一下他的描述,也可以跳过。你仍然可以通过否定没有任何异常。
【解决方案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;
}

【讨论】:

  • 为您的答案添加解释
【解决方案4】:

如果你有ListGetRange可以派上用场。

来自 MSDN 链接:

引用类型集合或其子集的浅拷贝 集合,仅包含对元素的引用 收藏。对象本身不会被复制。中的参考资料 新列表指向的对象与 原始列表。

Slice 函数可以是:

public static IEnumerable<T> Slice<T>(this List<T> source, int from, int to) => source.GetRange(from, to - from);

python slice 支持的负范围也可以处理,但会损失一些清洁度。

【讨论】:

    【解决方案5】:

    编写自定义扩展:

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

    【讨论】:

      【解决方案6】:

      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
      

      详细了解范围和索引herehere

      【讨论】:

      • List&lt;T&gt; 不使用Range 实现索引,Range 模式需要一个名为Slice 的成员,遗憾的是不支持扩展方法。
      【解决方案7】:

      这是一个扩展:

      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 }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-29
        • 1970-01-01
        • 2011-10-29
        • 2015-02-24
        • 2019-02-09
        相关资源
        最近更新 更多