Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create an array that points to only part of another array?

I have a huge array that contains reference type elements, and I want to create a lot of other arrays that essentially just point to specific parts of that one big array.

In other words, I want to create "indexers" or "pointers with lengths".

In C++ it's easy to do so using pointers and for each pointer assign a length, for example create a struct which contains a pointer with a length.

How can I achieve this in C#/.NET?

The whole point is to avoid copying anything, I just want pointers to specific parts in an array that already exists in memory.

Any ideas?

like image 772
SpaceMonkey Avatar asked Sep 04 '13 19:09

SpaceMonkey


People also ask

How do I point one array to another?

You would initialize the first element lets say as: int *first = new int; *first = 1; firstArray[0] = first; secondArray[0] = first; Then if you write *first = 20; both arrays will be updated. There is a problem with your question that you initialize first to 0 and then to 1.

How do you remove all elements from one array from another array?

For removing one array from another array in java we will use the removeAll() method. This will remove all the elements of the array1 from array2 if we call removeAll() function from array2 and array1 as a parameter.

Can you assign an array to another array?

Ensure that the two arrays have the same rank (number of dimensions) and compatible element data types. Use a standard assignment statement to assign the source array to the destination array. Do not follow either array name with parentheses.

How do I remove a specific part of an array?

Combining indexOf() and splice() Methods Pass the value of the element you wish to remove from your array into the indexOf() method to return the index of the element that matches that value in the array. Then make use of the splice() method to remove the element at the returned index.


3 Answers

Jon's suggestion of using ArraySegment<T> is likely what you want. If however you are wanting to represent a pointer to the interior of an array, the way you can in C++, here's some code for that. No warranty is expressed or implied, use at your own risk.

This code does not track the "length" of the interior pointer in any way, but it is quite easy to add that feature if you want.

internal struct ArrayPtr<T>
{
  public static ArrayPtr<T> Null { get { return default(ArrayPtr<T>); } }
  private readonly T[] source;
  private readonly int index;

  private ArrayPtr(ArrayPtr<T> old, int delta)
  {
    this.source = old.source;
    this.index = old.index + delta;
    Debug.Assert(index >= 0);
    Debug.Assert(index == 0 || this.source != null && index < this.source.Length);
  }

  public ArrayPtr(T[] source)
  {
    this.source = source;
    index = 0;
  }

  public bool IsNull()
  {
    return this.source == null;
  }

  public static bool operator <(ArrayPtr<T> a, ArrayPtr<T> b)
  {
    Debug.Assert(Object.ReferenceEquals(a.source, b.source));
    return a.index < b.index;
  }

  public static bool operator >(ArrayPtr<T> a, ArrayPtr<T> b)
  {
    Debug.Assert(Object.ReferenceEquals(a.source, b.source));
    return a.index > b.index;
  }

  public static bool operator <=(ArrayPtr<T> a, ArrayPtr<T> b)
  {
    Debug.Assert(Object.ReferenceEquals(a.source, b.source));
    return a.index <= b.index;
  }

  public static bool operator >=(ArrayPtr<T> a, ArrayPtr<T> b)
  {
    Debug.Assert(Object.ReferenceEquals(a.source, b.source));
    return a.index >= b.index;
  }

  public static int operator -(ArrayPtr<T> a, ArrayPtr<T> b)
  {
    Debug.Assert(Object.ReferenceEquals(a.source, b.source));
    return a.index - b.index;
  }

  public static ArrayPtr<T> operator +(ArrayPtr<T> a, int count)
  {
    return new ArrayPtr<T>(a, +count);
  }

  public static ArrayPtr<T> operator -(ArrayPtr<T> a, int count)
  {
    return new ArrayPtr<T>(a, -count);
  }

  public static ArrayPtr<T> operator ++(ArrayPtr<T> a)
  {
    return a + 1;
  }

  public static ArrayPtr<T> operator --(ArrayPtr<T> a)
  {
    return a - 1;
  }

  public static implicit operator ArrayPtr<T>(T[] x)
  {
    return new ArrayPtr<T>(x);
  }

  public static bool operator ==(ArrayPtr<T> x, ArrayPtr<T> y)
  {
    return x.source == y.source && x.index == y.index;
  }

  public static bool operator !=(ArrayPtr<T> x, ArrayPtr<T> y)
  {
    return !(x == y);
  }

  public override bool Equals(object x)
  {
    if (x == null) return this.source == null;
    var ptr = x as ArrayPtr<T>?;
    if (!ptr.HasValue) return false;
    return this == ptr.Value;
  }

  public override int GetHashCode()
  {
    unchecked
    {
      int hash = this.source == null ? 0 : this.source.GetHashCode();
      return hash + this.index;
    }
  }

  public T this[int index]
  {
    get { return source[index + this.index]; }
    set { source[index + this.index] = value; }
  }
}

Now we can do stuff like:

double[] arr = new double[10];
var p0 = (ArrayPtr<double>)arr;
var p5 = p0 + 5;
p5[0] = 123.4; // sets arr[5] to 123.4
var p7 = p0 + 7;
int diff = p7 - p5; // 2
like image 101
Eric Lippert Avatar answered Nov 07 '22 11:11

Eric Lippert


It sounds like you're looking for something like ArraySegment<T>. Contrary to my earlier thoughts, it does have an indexer and implement IEnumerable<T> etc - it's just done with explicit interfaces.

Sample code:

using System;
using System.Collections.Generic;

static class Test
{
    static void Main()
    {
        string[] original = { "The", "quick", "brown", "fox", "jumped", "over",
                "the", "lazy", "dog" };

        IList<string> segment = new ArraySegment<string>(original, 3, 4);
        Console.WriteLine(segment[2]); // over
        foreach (var word in segment)
        {
            Console.WriteLine(word); // fox jumped over the
        }
    }
}

EDIT: As noted in comments, ArraySegment<T> is only really "fully functional" in .NET 4.5. The .NET 4 version doesn't implement any interfaces.

like image 29
Jon Skeet Avatar answered Nov 07 '22 13:11

Jon Skeet


You could use LINQ:

yourArray.Skip(startIndex).Take(numberToTake)

The query is lazily evaluated.

like image 1
Нет войне Avatar answered Nov 07 '22 12:11

Нет войне