我有一个二维数组,
string[,] table = {
{ "aa", "aaa" },
{ "bb", "bbb" }
};
我希望foreach
像这样通过它,
foreach (string[] row in table)
{
Console.WriteLine(row[0] + " " + row[1]);
}
但是,我收到了错误:
无法将类型字符串转换为字符串[]
有没有办法可以达到我想要的效果,即使用迭代器变量迭代数组的第一个维度,返回该行的一维数组?
答案 0 :(得分:57)
多维数组不可枚举。只是按照老式的方式进行迭代:
for (int i = 0; i < table.GetLength(0); i++)
{
Console.WriteLine(table[i, 0] + " " + table[i, 1]);
}
答案 1 :(得分:24)
如果你这样定义你的数组:
string[][] table = new string[][] { new string[] { "aa", "aaa" }, new string[]{ "bb", "bbb" } };
然后你可以使用foreach循环。
答案 2 :(得分:23)
正如其他人所建议的那样,您可以使用嵌套的for循环或将多维数组重新声明为锯齿状的数组。
但是,我认为有必要指出多维数组 是可枚举的,只是不是你想要的方式。例如:
string[,] table = {
{ "aa", "aaa" },
{ "bb", "bbb" }
};
foreach (string s in table)
{
Console.WriteLine(s);
}
/* Output is:
aa
aaa
bb
bbb
*/
答案 3 :(得分:15)
更新:我有一些时间在我的手上,所以......我继续前进并充实了这个想法。请参阅下面的代码。
这是一个疯狂的答案:
你可以做你正在寻找的东西 - 基本上将二维数组视为一个带有行的表 - 通过编写一个静态方法(可能是一个扩展方法)来获取{ {1}}并返回T[,]
。但这需要将基础表的每个“行”复制到一个新数组中。
一个或许更好(虽然更复杂)的方法是实际编写一个实现IEnumerable<T[]>
的类作为二维数组的单个“行”的包装器(你可能会设置{{1} } to true并且只为IList<T>
属性实现getter,可能IsReadOnly
和this[int]
;其他所有内容都可以抛出Count
)。然后,您的静态/扩展方法可以返回GetEnumerator
并提供延迟执行。
这样你就可以编写与你拥有的代码非常相似的代码:
NotSupportedException
只是一个想法。
实施建议:
IEnumerable<IList<T>>
...现在我想我应该在剩下的时间里给StackOverflow一个休息时间;)
答案 4 :(得分:4)
这取决于您如何定义多维数组。这有两个选择:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
// First
string[,] arr1 = {
{ "aa", "aaa" },
{ "bb", "bbb" }
};
// Second
string[][] arr2 = new[] {
new[] { "aa", "aaa" },
new[] { "bb", "bbb" }
};
// Iterate through first
for (int x = 0; x <= arr1.GetUpperBound(0); x++)
for (int y = 0; y <= arr1.GetUpperBound(1); y++)
Console.Write(arr1[x, y] + "; ");
Console.WriteLine(Environment.NewLine);
// Iterate through second second
foreach (string[] entry in arr2)
foreach (string element in entry)
Console.Write(element + "; ");
Console.WriteLine(Environment.NewLine);
Console.WriteLine("Press any key to finish");
Console.ReadKey();
}
}
}
答案 5 :(得分:3)
string[][] table = { ... };
答案 6 :(得分:2)
使用LINQ你可以这样做:
var table_enum = table
// Convert to IEnumerable<string>
.OfType<string>()
// Create anonymous type where Index1 and Index2
// reflect the indices of the 2-dim. array
.Select((_string, _index) => new {
Index1 = (_index / 2),
Index2 = (_index % 2), // ← I added this only for completeness
Value = _string
})
// Group by Index1, which generates IEnmurable<string> for all Index1 values
.GroupBy(v => v.Index1)
// Convert all Groups of anonymous type to String-Arrays
.Select(group => group.Select(v => v.Value).ToArray());
// Now you can use the foreach-Loop as you planned
foreach(string[] str_arr in table_enum) {
// …
}
通过使用GroupBy中的Index2而不是Index1,也可以使用foreach循环遍历列而不是行。如果你不知道数组的维度,那么你必须使用GetLength()方法确定维度并在商中使用该值。
答案 7 :(得分:2)
这是一个简单的扩展方法,可以将每一行作为IEnumerable<T>
返回。这样做的好处是不使用任何额外的内存:
public static class Array2dExt
{
public static IEnumerable<IEnumerable<T>> Rows<T>(this T[,] array)
{
for (int r = array.GetLowerBound(0); r <= array.GetUpperBound(0); ++r)
yield return row(array, r);
}
static IEnumerable<T> row<T>(T[,] array, int r)
{
for (int c = array.GetLowerBound(1); c <= array.GetUpperBound(1); ++c)
yield return array[r, c];
}
}
样本用法:
static void Main()
{
string[,] siblings = { { "Mike", "Amy" }, { "Mary", "Albert" }, {"Fred", "Harry"} };
foreach (var row in siblings.Rows())
Console.WriteLine("{" + string.Join(", ", row) + "}");
}
答案 8 :(得分:1)
请记住,多维数组就像一个表。每个条目都没有 x 元素和 y 元素;你有一个字符串(例如)table[1,2]
。
因此,每个条目仍然只有一个字符串(在您的示例中),它只是一个特定x / y值的条目。因此,要在table[1, x]
处获取两个条目,您将执行嵌套for循环。类似下面的内容(未测试,但应该关闭)
for (int x = 0; x < table.Length; x++)
{
for (int y = 0; y < table.Length; y += 2)
{
Console.WriteLine("{0} {1}", table[x, y], table[x, y + 1]);
}
}
答案 9 :(得分:1)
string[][] languages = new string[2][];
languages[0] = new string[2];
languages[1] = new string[3];
// inserting data into double dimensional arrays.
for (int i = 0; i < 2; i++)
{
languages[0][i] = "Jagged"+i.ToString();
}
for (int j = 0; j < 3; j++)
{
languages[1][j] = "Jag"+j.ToString();
}
// doing foreach through 2 dimensional arrays.
foreach (string[] s in languages)
{
foreach (string a in s)
{
Console.WriteLine(a);
}
}
答案 10 :(得分:0)
由于涉及内存使用,我不是这种方法的忠实粉丝,但如果你使用它产生的数组,那就不是浪费了。
public static void ForEachRow<T>(this T[,] list, Action<int, T[]> action)
{
var len = list.GetLength(0);
var sub = list.GetLength(1);
T[] e;
int i, j;
for (i = 0; i < len; i++)
{
e = new T[sub];
for (j = 0; j < sub; j++)
{
e[j] = list[i, j];
}
action(i, e);
}
}
实现:
var list = new[,]{0x0, 0x1, 0x2, 0x4, 0x8};
list.ForEachRow((i, row) =>
{
for (var j = 0; j < row.Length; j++)
{
Console.WriteLine("[{0},{1}]: {2}", i, j, row[j]);
}
});
我发现的另一个解决方案是内存密集程度较低,但会占用更多CPU,尤其是当数组条目的维度较大时。
public static void ForEachRow<T>(this T[,] list, Action<int, IEnumerable<T>> action)
{
var len = list.GetLength(0);
var sub = list.GetLength(1);
int i, j;
IEnumerable<T> e;
for (i = 0; i < len; i++)
{
e = Enumerable.Empty<T>();
for (j = 0; j < sub; j++)
{
e = e.Concat(AsEnumerable(list[i, j]));
}
action(i, e);
}
}
private static IEnumerable<T> AsEnumerable<T>(T add)
{
yield return add;
}
实现:
var list = new[,]{0x0, 0x1, 0x2, 0x4, 0x8};
list.ForEachRow((i, row) =>
{
var j = 0;
forrach (var o in row)
{
Console.WriteLine("[{0},{1}]: {2}", i, j, o);
++j;
}
});
作为一个整体,我发现第一个选项更直观,特别是如果你想通过它的索引器访问生成的数组。
在一天结束时,这只是眼睛糖果,这两种方法都不应该用于直接访问源数组;
for (var i = 0; i < list.GetLength(0); i++)
{
foreach (var j = 0; j < list.GetLength(1); j++)
{
Console.WriteLine("[{0},{1}]: {2}", i, j, list[i, j]);
}
}
答案 11 :(得分:0)
我试试这个。我希望能帮到你。它适用于
static void Main()
{
string[,] matrix = {
{ "aa", "aaa" },
{ "bb", "bbb" }
};
int index = 0;
foreach (string element in matrix)
{
if (index < matrix.GetLength(1))
{
Console.Write(element);
if (index < (matrix.GetLength(1) - 1))
{
Console.Write(" ");
}
index++;
}
if (index == matrix.GetLength(1))
{
Console.Write("\n");
index = 0;
}
}