39

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?

Kiril
  • 39,672
  • 31
  • 167
  • 226
  • 1
    It sounds like you want to create an array that references a slice of the array. I don't think that's possible. – Gabe Jan 26 '11 at 06: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! :) – Kiril Jan 26 '11 at 07:00
  • 2
    I just noticed that my question is a duplicate: http://stackoverflow.com/questions/1406083/array-slice-in-c – Kiril Jan 26 '11 at 07:19

4 Answers4

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]);
        }
    }
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 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! – Kiril Jan 26 '11 at 07:02
  • _(You got it, never mind right-hand comment)_ -- Good job, +1 – Brad Christie Jan 26 '11 at 07:08
15

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];
    }
}
Community
  • 1
  • 1
tsul
  • 1,401
  • 1
  • 18
  • 22
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.

drharris
  • 11,194
  • 5
  • 43
  • 56
  • 2
    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? – barlop Dec 24 '15 at 11:23
1

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();
Allen Aston
  • 521
  • 5
  • 9