2008-10-24 1 views
12

Скажем, у меня есть прямоугольный массив строк - не рваная массивКаков наилучший способ извлечения одномерного массива из прямоугольного массива в C#?

string[,] strings = new string[8, 3]; 

Какой самый лучший способ извлечения одномерный массив из этого (либо одной строки или одного столбца)? Я могу сделать это с помощью цикла for, конечно, но я надеюсь, что .NET будет иметь более элегантный способ построения.

Бонусные баллы для преобразования выделенного массива строк в массив объектов.

ответ

7

Для прямоугольного массива:

string[,] rectArray = new string[3,3] { 
    {"a", "b", "c"}, 
    {"d", "e", "f"}, 
    {"g", "h", "i"} }; 

var rectResult = rectArray.Cast<object>().ToArray(); 

А для зазубренным массива:

string[][] jaggedArray = { 
    new string[] {"a", "b", "c", "d"}, 
    new string[] {"e", "f"}, 
    new string[] {"g", "h", "i"} }; 

var jaggedResult = jaggedArray.SelectMany(s => s).Cast<object>().ToArray(); 
1

LINQ ответ

static object[] GetColumn(string[][] source, int col) { 
    return source.Iterate().Select(x => source[x.Index][col]).Cast<object>().ToArray(); 
} 
static object[] GetRow(string[][] source, int row) { 
    return source.Skip(row).First().Cast<object>().ToArray(); 
} 
public class Pair<T> { 
    public int Index; 
    public T Value; 
    public Pair(int i, T v) { 
     Index = i; 
     Value = v; 
    } 
} 
static IEnumerable<Pair<T>> Iterate<T>(this IEnumerable<T> source) { 
    int index = 0; 
    foreach (var cur in source) { 
     yield return new Pair<T>(index, cur); 
     index++; 
    } 
} 
+0

Я не думаю, что это делает то, что было предложено для («либо одной строки или одного столбца»). – 2008-10-24 05:31:10

+0

Не LINQ будет использовать цикл внутри? – Rohit 2008-10-24 05:39:57

+0

Спасибо, что указали, что Джон. Я прочитал эту часть ответа. – JaredPar 2008-10-24 06:13:14

13

Вы можете привести массив строк в массив объектов тривиальным - в другую сторону не работает. Фактическое извлечение имеет, чтобы использовать цикл for, хотя, насколько я вижу: Array.Copy требует, чтобы исходные и целевые ранги были одинаковыми, а Buffer.BlockCopy работает только для массивов типов значений. Это кажется странным, хотя ...

Вы можете использовать LINQ, чтобы добавить строку или столбец в один оператор, хотя он будет неэффективным (поскольку он будет внутренне создавать список, а затем преобразовать его в array - если вы сделаете это самостоятельно, вы можете предварительно распределить массив до нужного размера и скопировать напрямую).

Копирование строки (rowNum является строка для копирования):

object[] row = Enumerable.Range(0, rowLength) 
         .Select(colNum => (object) stringArray[rowNum, colNum]) 
         .ToArray(); 

Копирование столбца (colNum это столбец должен быть скопирован):

object[] column = Enumerable.Range(0, columnLength) 
          .Select(rowNum => (object) stringArray[rowNum, colNum]) 
          .ToArray(); 

Я не уверен, что это действительно лучше/проще, чем цикл foreach, особенно если вы пишете метод ExtractRow и метод ExtractColumn и повторно их используете.

+0

Просто убедитесь, что я не изобретаю колесо. Эта конкретная задача, конечно, не встречается в природе достаточно часто, чтобы гарантировать встроенную функцию. – MusiGenesis 2008-10-24 05:46:51

4

Я просто хотел бы уточнить (с учетом примера и того, что задают).

Невыровненный массив представляет собой массив массивов и объявляется следующим образом:

string[][] data = new string[3][]; 
data[0] = new string[] { "0,[0]", "0,[1]", "0,[2]" }; 
data[1] = new string[] { "1,[0]", "1,[1]", "1,[2]" ]; 
data[2] = new string[] { "2,[0]", "1,[1]", "1,[2]" }; 

в сравнении с прямоугольного массива определяется как единый массив, который содержит несколько измерений:

string[,] data = new string[3,3]; 
data[0,0] = "0,0"; 
data[0,1] = "0,1"; 
data[0,2] = "0,2"; 
...etc 

Из-за этого, зубчатый массив IQueryable/IEnumerab le, потому что вы можете перебирать его для получения массива на каждой итерации. В то время как прямоугольный массив является не IQueryable/IEnumerable, потому что элементы рассматриваются в полном измерении (0,0 0,1..etc), так что вы не будете иметь возможность использовать Linq или любые предопределенные функции, созданные для Массив в этом случае.

Хотя вы можете перебрать массив один раз (и добиться того, что вы хотите), как это:

/// INPUT: rowIndex, OUTPUT: An object[] of data for that row 
int colLength = stringArray.GetLength(1); 
object[] rowData = new object[colLength]; 
for (int col = 0; col < colLength; col++) { 
    rowData[col] = stringArray[rowIndex, col] as object; 
} 
return rowData; 

/// INPUT: colIndex, OUTPUT: An object[] of data for that column 
int rowLength = stringArray.GetLength(0); 
object[] colData = new object[rowLength]; 
for (int row = 0; r < rowLength; row++) { 
    colData[row] = stringArray[row, colIndex] as object; 
} 
return colData; 

Надеется, что это помогает :)

1

Ряды могут быть легко скопированы с помощью Array.Copy:

 int[][] arDouble = new int[2][]; 
     arDouble[0] = new int[2]; 
     arDouble[1] = new int[2]; 
     arDouble[0][0] = 1; 
     arDouble[0][1] = 2; 
     arDouble[1][0] = 3; 
     arDouble[1][1] = 4; 

     int[] arSingle = new int[arDouble[0].Length]; 

     Array.Copy(arDouble[0], arSingle, arDouble[0].Length); 

Это скопирует первую строку в единый размерный массив.

0

я сделал метод Удлинитель. Я не знаю о производительности.

public static class ExtensionMethods 
{ 
    public static string[] get1Dim(this string[,] RectArr, int _1DimIndex , int _2DimIndex ) 
    { 
     string[] temp = new string[RectArr.GetLength(1)]; 

     if (_2DimIndex == -1) 
     { 
      for (int i = 0; i < RectArr.GetLength(1); i++) 
      { temp[i] = RectArr[_1DimIndex, i]; } 
     } 
     else 
     { 
      for (int i = 0; i < RectArr.GetLength(0); i++) 
      { temp[i] = RectArr[ i , _2DimIndex]; } 
     } 

     return temp; 
     } 
} 

использование

// we now have this funtionaliy RectArray[1, * ] 
//          -1 means ALL  
string[] _1stRow = RectArray.get1Dim(0, -1) ;  
string[] _2ndRow = RectArray.get1Dim(1, -1) ; 

string[] _1stCol = RectArray.get1Dim(-1, 0) ;  
string[] _2ndCol = RectArray.get1Dim(-1, 1) ;