C# 从现有数组中获取子数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/943635/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 03:54:26  来源:igfitidea点击:

Getting a sub-array from an existing array

c#.netarrays

提问by user88637

I have an array X of 10 elements. I would like to create a new array containing all the elements from X that begin at index 3 and ends in index 7. Sure I can easily write a loop that will do it for me but I would like to keep my code as clean as possible. Is there a method in C# that can do it for me?

我有一个包含 10 个元素的数组 X。我想创建一个新数组,其中包含 X 中从索引 3 开始并以索引 7 结束的所有元素。当然,我可以轻松编写一个循环来为我执行此操作,但我希望尽可能保持代码整洁. C# 中有没有可以为我做的方法?

Something like (pseudo code):

类似(伪代码):

Array NewArray = oldArray.createNewArrayFromRange(int BeginIndex , int EndIndex)

Array.Copydoesn't fit my needs. I need the items in the new array to be clones. Array.copyis just a C-Style memcpyequivalent, it's not what I'm looking for.

Array.Copy不符合我的需要。我需要新数组中的项目是克隆。Array.copy只是一个 C 风格的memcpy等价物,这不是我要找的。

采纳答案by Marc Gravell

You could add it as an extension method:

您可以将其添加为扩展方法:

public static T[] SubArray<T>(this T[] data, int index, int length)
{
    T[] result = new T[length];
    Array.Copy(data, index, result, 0, length);
    return result;
}
static void Main()
{
    int[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    int[] sub = data.SubArray(3, 4); // contains {3,4,5,6}
}


Update re cloning (which wasn't obvious in the original question). If you reallywant a deep clone; something like:

更新重新克隆(这在原始问题中并不明显)。如果你真的想要一个深度克隆;就像是:

public static T[] SubArrayDeepClone<T>(this T[] data, int index, int length)
{
    T[] arrCopy = new T[length];
    Array.Copy(data, index, arrCopy, 0, length);
    using (MemoryStream ms = new MemoryStream())
    {
        var bf = new BinaryFormatter();
        bf.Serialize(ms, arrCopy);
        ms.Position = 0;
        return (T[])bf.Deserialize(ms);
    }
}

This does require the objects to be serializable ([Serializable]or ISerializable), though. You could easily substitute for any other serializer as appropriate - XmlSerializer, DataContractSerializer, protobuf-net, etc.

不过,这确实需要对象可序列化([Serializable]ISerializable)。您可以根据需要轻松替换任何其他序列化程序 - XmlSerializerDataContractSerializer、 protobuf-net 等。

Note that deep clone is tricky without serialization; in particular, ICloneableis hard to trust in most cases.

请注意,没有序列化的深度克隆很棘手;特别是,ICloneable在大多数情况下很难信任。

回答by Jon Skeet

You can use Array.Copy(...)to copy into the new array after you've created it, but I don't think there's a method which creates the new array andcopies a range of elements.

Array.Copy(...)创建新数组后,您可以使用它复制到新数组中,但我认为没有一种方法可以创建新数组复制一系列元素。

If you're using .NET 3.5 you coulduse LINQ:

如果您使用 .NET 3.5,您可以使用 LINQ:

var newArray = array.Skip(3).Take(5).ToArray();

but that will be somewhat less efficient.

但这会降低效率。

See this answerto a similar question for options for more specific situations.

有关更具体情况的选项,请参阅对类似问题的回答

回答by crauscher

Array.ConstrainedCopy will work.

Array.ConstrainedCopy 将起作用。

public static void ConstrainedCopy (
    Array sourceArray,
    int sourceIndex,
    Array destinationArray,
    int destinationIndex,
    int length
)

回答by Sean

I think that the code you are looking for is:

我认为您正在寻找的代码是:

Array.Copy(oldArray, 0, newArray, BeginIndex, EndIndex - BeginIndex)

Array.Copy(oldArray, 0, newArray, BeginIndex, EndIndex - BeginIndex)

回答by RandomNickName42

You can do this fairly easially;

你可以很容易地做到这一点;

    object[] foo = new object[10];
    object[] bar = new object[7];   
    Array.Copy(foo, 3, bar, 0, 7);  

回答by Guffa

As an alternative to copying the data you can make a wrapper that gives you access to a part of the original array as if it was a copy of the part of the array. The advantage is that you don't get another copy of the data in memory, and the drawback is a slight overhead when accessing the data.

作为复制数据的替代方法,您可以制作一个包装器,让您可以访问原始数组的一部分,就像它是数组部分的副本一样。优点是您不会在内存中获得数据的另一个副本,缺点是访问数据时开销很小。

public class SubArray<T> : IEnumerable<T> {

   private T[] _original;
   private int _start;

   public SubArray(T[] original, int start, int len) {
      _original = original;
      _start = start;
      Length = len;
   }

   public T this[int index] {
      get {
         if (index < 0 || index >= Length) throw new IndexOutOfRangeException();
         return _original[_start + index];
      }
   }

   public int Length { get; private set; }

   public IEnumerator<T> GetEnumerator() {
      for (int i = 0; i < Length; i++) {
        yield return _original[_start + i];
      }
   }

   IEnumerator IEnumerable.GetEnumerator() {
      return GetEnumerator();
   }

}

Usage:

用法:

int[] original = { 1, 2, 3, 4, 5 };
SubArray<int> copy = new SubArray<int>(original, 2, 2);

Console.WriteLine(copy.Length); // shows: 2
Console.WriteLine(copy[0]); // shows: 3
foreach (int i in copy) Console.WriteLine(i); // shows 3 and 4

回答by zvolkov

I see you want to do Cloning, not just copying references. In this case you can use .Selectto project array members to their clones. For example, if your elements implemented IClonableyou could do something like this:

我看到你想做克隆,而不仅仅是复制引用。在这种情况下,您可以使用.Select将数组成员投影到其克隆。例如,如果您实现了元素,IClonable您可以执行以下操作:

var newArray = array.Skip(3).Take(5).Select(eachElement => eachElement.Clone()).ToArray();

Note: This solution requires .NET Framework 3.5.

注意:此解决方案需要 .NET Framework 3.5。

回答by ShuggyCoUk

Building on Marc's answer but adding the desired cloning behaviour

以 Marc 的答案为基础,但添加了所需的克隆行为

public static T[] CloneSubArray<T>(this T[] data, int index, int length)
    where T : ICloneable
{
    T[] result = new T[length];
    for (int i = 0; i < length; i++)
    { 
        var original = data[index + i];
        if (original != null)
            result[i] = (T)original.Clone();            
    return result;
}

And if implementing ICloneable is too much like hard work a reflective one using H?vard Stranden's Copyable libraryto do the heavy lifting required.

如果实现 ICloneable 太像艰苦的工作,那么使用H?vard Stranden 的可复制库来完成所需的繁重工作。

using OX.Copyable;

public static T[] DeepCopySubArray<T>(
    this T[] data, int index, int length)
{
    T[] result = new T[length];
    for (int i = 0; i < length; i++)
    { 
        var original = data[index + i];
        if (original != null)
            result[i] = (T)original.Copy();            
    return result;
}

Note that the OX.Copyable implementation works with any of:

请注意,OX.Copyable 实现适用于以下任何一项:

For the automated copy to work, though, one of the following statements must hold for instance:

  • Its type must have a parameterless constructor, or
  • It must be a Copyable, or
  • It must have an IInstanceProvider registered for its type.

但是,要使自动复制工作,例如必须满足以下语句之一:

  • 它的类型必须有一个无参数的构造函数,或者
  • 它必须是可复制的,或
  • 它必须为其类型注册一个 IInstanceProvider。

So this should cover almost any situation you have. If you are cloning objects where the sub graph contains things like db connections or file/stream handles you obviously have issues but that it true for any generalized deep copy.

因此,这应该涵盖您遇到的几乎所有情况。如果您要克隆对象,其中子图包含诸如 db 连接或文件/流句柄之类的内容,那么您显然会遇到问题,但对于任何广义深层复制来说都是如此。

If you want to use some other deep copy approach instead this article lists several othersso I would suggest not trying to write your own.

如果您想使用其他一些深复制方法,本文列出了其他几种方法,因此我建议您不要尝试自己编写。

回答by Thorarin

There's no single method that will do what you want. You will need to make a clone method available for the class in your array. Then, if LINQ is an option:

没有一种方法可以满足您的需求。您需要为数组中的类提供一个克隆方法。然后,如果 LINQ 是一个选项:

Foo[] newArray = oldArray.Skip(3).Take(5).Select(item => item.Clone()).ToArray();

class Foo
{
    public Foo Clone()
    {
        return (Foo)MemberwiseClone();
    }
}

回答by Philippe Leybaert

Cloning elements in an array is not something that can be done in a universal way. Do you want deep cloning or a simple copy of all members?

克隆数组中的元素不是通用的方法。你想要深度克隆还是所有成员的简单副本?

Let's go for the "best effort" approach: cloning objects using the ICloneable interface or binary serialization:

让我们采用“尽力而为”的方法:使用 ICloneable 接口或二进制序列化克隆对象:

public static class ArrayExtensions
{
  public static T[] SubArray<T>(this T[] array, int index, int length)
  {
    T[] result = new T[length];

    for (int i=index;i<length+index && i<array.Length;i++)
    {
       if (array[i] is ICloneable)
          result[i-index] = (T) ((ICloneable)array[i]).Clone();
       else
          result[i-index] = (T) CloneObject(array[i]);
    }

    return result;
  }

  private static object CloneObject(object obj)
  {
    BinaryFormatter formatter = new BinaryFormatter();

    using (MemoryStream stream = new MemoryStream())
    {
      formatter.Serialize(stream, obj);

      stream.Seek(0,SeekOrigin.Begin);

      return formatter.Deserialize(stream);
    }
  }
}

This is not a perfect solution, because there simply is none that will work for any type of object.

这不是一个完美的解决方案,因为根本没有一种适用于任何类型的对象。