[英]What's the best way to extract a one-dimensional array from a rectangular array in C#?
Say I have a rectangular string array - not a jagged array 假设我有一个矩形字符串数组 - 不是锯齿状数组
string[,] strings = new string[8, 3];
What's the best way to extract a one-dimensional array from this (either a single row or a single column)? 从中提取一维数组(单行还是单列)的最佳方法是什么? I can do this with a for loop, of course, but I'm hoping .NET has a more elegant way built in. 当然,我可以使用for循环执行此操作,但我希望.NET内置更优雅的方式。
Bonus points for converting the extracted string array to an object array. 用于将提取的字符串数组转换为对象数组的加值点。
You can cast a string array to an object array trivially - going the other way doesn't work. 您可以简单地将字符串数组转换为对象数组 - 另一种方式不起作用。 The actual extraction has to use a for loop though, as far as I can see: Array.Copy
requires the source and target ranks to be the same, and Buffer.BlockCopy
only works for value type arrays. 实际的提取必须使用for循环,据我Array.Copy
: Array.Copy
要求源和目标等级相同,而Buffer.BlockCopy
仅适用于值类型数组。 It does seem odd though... 虽然看起来很奇怪......
You can use LINQ to extra a row or column in a single statement, although it will be inefficient (as it'll build up a list internally, then have to convert it to an array - if you do it yourself you can preallocate the array to the right size and copy directly). 您可以在单个语句中使用LINQ来添加行或列,尽管它效率低(因为它会在内部构建列表,然后必须将其转换为数组 - 如果您自己执行,则可以预先分配数组大小合适并直接复制)。
Copying a row ( rowNum
is the row to be copied): 复制行( rowNum
是要复制的行):
object[] row = Enumerable.Range(0, rowLength)
.Select(colNum => (object) stringArray[rowNum, colNum])
.ToArray();
Copying a column ( colNum
is the column to be copied): 复制列( colNum
是要复制的列):
object[] column = Enumerable.Range(0, columnLength)
.Select(rowNum => (object) stringArray[rowNum, colNum])
.ToArray();
I'm not sure that this is really any better/simpler than a foreach loop though - particularly if you write an ExtractRow
method and an ExtractColumn
method and reuse them. 我不确定这是否比foreach循环更好/更简单 - 特别是如果你编写一个ExtractRow
方法和一个ExtractColumn
方法ExtractRow
用它们。
For a rectangular array: 对于矩形阵列:
string[,] rectArray = new string[3,3] {
{"a", "b", "c"},
{"d", "e", "f"},
{"g", "h", "i"} };
var rectResult = rectArray.Cast<object>().ToArray();
And for a jagged array: 对于锯齿状阵列:
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();
I'd just like to clarify (given the example and what's being asked). 我想澄清一下(给出例子以及被问到的内容)。
A jagged array is an array of arrays and is declared like so: 锯齿状数组是一个数组数组,声明如下:
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]" };
Versus a rectangular array being defined as a single array that holds multiple dimensions: 与矩形数组相对应 ,定义为包含多个维度的单个数组:
string[,] data = new string[3,3];
data[0,0] = "0,0";
data[0,1] = "0,1";
data[0,2] = "0,2";
...etc
Because of this, a jagged array is IQueryable/IEnumerable because you can iterate over it to receive an array at each iteration. 因此, 锯齿状数组是IQueryable / IEnumerable,因为您可以迭代它以在每次迭代时接收数组。 Whereas a rectangular array is not IQueryable/IEnumerable because elements are addressed in full dimension (0,0 0,1..etc) so you won't have the ability to use Linq or any predefined functions created for Array in that case. 而矩形数组 不是 IQueryable / IEnumerable,因为元素以全维度(0,0 0,1..etc)进行寻址,因此在这种情况下您将无法使用Linq或为Array创建的任何预定义函数。
Though you can iterate over the array once (and achieve what you want) like this: 虽然您可以迭代一次数组(并实现您想要的),如下所示:
/// 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;
Hope this helps :) 希望这可以帮助 :)
LINQ is the answer 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++;
}
}
Rows can be copied easily using Array.Copy: 可以使用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);
This will copy the first row into the single Dimension array. 这会将第一行复制到单个Dimension数组中。
i made extention method. 我做了扩展方法。 i dont know about the performance . 我不知道性能。
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;
}
}
usage 用法
// 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) ;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.