42

I'm trying to figure out how to get a single dimension from a multidimensional array (for the sake of argument, let's say it's 2D), I have a multidimensional array:

double[,] d = new double[,] { { 1, 2, 3, 4, 5 }, { 5, 4, 3, 2, 1 } };

If it was a jagged array, I would simply call d[0] and that would give me an array of {1, 2, 3, 4, 5}, is there a way I can achieve the same with a 2D array?

3
  • 1
    It sounds like you want to create an array that references a slice of the array. I don't think that's possible. Commented Jan 26, 2011 at 6:56
  • @Gabe, yah, I looked through the documentation and I couldn't see anything that would help me get a slice, so I decided to confirm with the community. Thanks for the info! :) Commented Jan 26, 2011 at 7:00
  • 2
    I just noticed that my question is a duplicate: stackoverflow.com/questions/1406083/array-slice-in-c Commented Jan 26, 2011 at 7:19

5 Answers 5

25

No. You could of course write a wrapper class that represents a slice, and has an indexer internally - but nothing inbuilt. The other approach would be to write a method that makes a copy of a slice and hands back a vector - it depends whether you want a copy or not.

using System;
static class ArraySliceExt
{
    public static ArraySlice2D<T> Slice<T>(this T[,] arr, int firstDimension)
    {
        return new ArraySlice2D<T>(arr, firstDimension);
    }
}
class ArraySlice2D<T>
{
    private readonly T[,] arr;
    private readonly int firstDimension;
    private readonly int length;
    public int Length { get { return length; } }
    public ArraySlice2D(T[,] arr, int firstDimension)
    {
        this.arr = arr;
        this.firstDimension = firstDimension;
        this.length = arr.GetUpperBound(1) + 1;
    }
    public T this[int index]
    {
        get { return arr[firstDimension, index]; }
        set { arr[firstDimension, index] = value; }
    }
}
public static class Program
{
    static void Main()
    {
        double[,] d = new double[,] { { 1, 2, 3, 4, 5 }, { 5, 4, 3, 2, 1 } };
        var slice = d.Slice(0);
        for (int i = 0; i < slice.Length; i++)
        {
            Console.WriteLine(slice[i]);
        }
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

thanks for the info... after not finding anything inbuilt I assumed that I'd have to write a wrapper, but I wanted to make sure I didn't miss anything. Thanks again!
(You got it, never mind right-hand comment) -- Good job, +1
18

Improved version of that answer:

public static IEnumerable<T> SliceRow<T>(this T[,] array, int row)
{
    for (var i = array.GetLowerBound(1); i <= array.GetUpperBound(1); i++)
    {
        yield return array[row, i];
    }
}

public static IEnumerable<T> SliceColumn<T>(this T[,] array, int column)
{
    for (var i = array.GetLowerBound(0); i <= array.GetUpperBound(0); i++)
    {
        yield return array[i, column];
    }
}

1 Comment

Exactly what I need. IEnumerable.
3

Rectangular arrays are not built for this purpose. If you need that type of functionality, you should switch to a jagged array. It is pretty simple to write a function that will convert a rectangular array into a jagged one.

You could also simply rebuild that array by calling GetLength(int dimension) on the appropriate dimension, and then indexing it properly to retrieve each value. It would be cheaper than converting the entire array, but the cheapest option is to change it to use jagged arrays.

3 Comments

you write "It is pretty simple to write a function that will convert a rectangular array into a jagged one." <--- but perhaps quite inefficient if a large array, because you have to scan the whole array? how do you convert rectangular to jagged without rebuilding it?
You won't be able get both a column and a row easily in a jagged array. If you need both, I feel that going to jagged array provides no benefit. Would you agree?
@barlop Indeed a jagged array is basically just an array containing references to a bunch of 1-dimensional arrays in memory. Normally it would require the new allocation of the entire 2-dimensional array, which may result in scattered memory locations even (which is inefficient). And I just checked, it's not possible to avoid copying memory because even in unsafe environments because it is not possible to create an array using existing memory without copying data. I haven't researched it further though... I can imagine there is a solution to that though.
2

This should replicate the a[r] functionality of a jagged array:

T[] Slice<T>(T[,] a, int r) => Enumerable.Range(0, a.GetUpperBound(1) + 1).Select(i => a[r, i]).ToArray();

1 Comment

Instead of GetUpperBound(1) + 1 it's clearer to just use GetLength(1).
0

Good answers are already given, but I recently worked on it and created these methods into my libraries:

/// <summary> Iterates the given 2-dimensional array's specified row. A row is all values contained when the left hand index is identical. </summary>
public static IEnumerable<T> IterateRow<T> (T[,] array, int row)
{
    int upperBound = array.GetUpperBound (1);
    for (int i = array.GetLowerBound (1); i <= upperBound; i++)
    {
        yield return array[row, i];
    }
}

/// <summary> Iterates the given 2-dimensional array's specified column. A column is all values contained when the right hand index is identical. </summary>
public static IEnumerable<T> IterateColumn<T> (T[,] array, int column)
{
    int upperBound = array.GetUpperBound (0);
    for (int i = array.GetLowerBound (0); i <= upperBound; i++)
    {
        yield return array[i, column];
    }
}

/// <summary> Returns the given 2-dimensional array's specified row. A row is all values contained when the left hand index is identical. </summary>
public static T[] SliceRow<T> (T[,] array, int row)
{
    int upperBound = array.GetUpperBound (1);
    T[] slice = new T[upperBound + 1];
    for (int i = array.GetLowerBound (1); i <= upperBound; i++)
    {
        slice[i] = array[row, i];
    }
    return slice;
}

/// <summary> Returns the given 2-dimensional array's specified column. A column is all values contained when the right hand index is identical. </summary>
public static T[] SliceColumn<T> (T[,] array, int column)
{
    int upperBound = array.GetUpperBound (0);
    T[] slice = new T[upperBound + 1];
    for (int i = array.GetLowerBound (0); i <= upperBound; i++)
    {
        slice[i] = array[i, column];
    }
    return slice;
}

These are slightly refined. For example "i <= array.GetUpperBound(1)" as written in the other answer would run that method with every iteration. Also there are versions that provide the 1-dimensional arrays directly. I prefer to use the term "Iterate" in method names for iterative methods. I am also no fan of method extensions any more - you may lose overview at some point if they stack up too much. And given that you would (and should) need to add the namespace anyway, it doesn't really speed things up much. In my case I just use "int[] firstRow = UtilityFunctions.SliceRow (myArray, 0);".

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.