[英]c# find row index of specific numbers in a 2 dimensonal array
有一个输入:
8 4 6 6 6 6 6 6
7 5 7 6 6 6 6 5
6 6 6 5 5 5 5 6
8 6 8 7 7 7 7 6
8 6 6 6 6 6 6 6
8 6 6 6 6 6 6 1
我必须在每一列中找到最大的数字并获取它们的行索引,如果一列中有多个相同的最大数字,我必须获取它们的所有行索引,并将它们放入一个数组中,但是如果有多个相同的行索引我只需要一个,我必须将它们按升序排列。
第一列的最大数字是 8,所以第一列的索引是 0、3、4、5。第二列的最大数字是 6,所以第二列的索引是 2、3、4、5 但我已经有 3、4 和 5,所以我只需要 2 最后我应该有 0、2、3、4、5。
while (p < M) //Getting the greatest numbers of each column
{
for (int l = 0; l < N; l++)
{
if (matrix[l, p] > max)
{
max = matrix[l, p];
}
}
greatestNum[p] = max;
max = 0;
p++;
}
我只需要获取索引和没有重复的帮助。 我可以自己做升序。 感谢您的每一次帮助。
您可以使用HashSet<int>
来存储唯一行:
using System.Linq;
...
private static int[] myIndexes(int[,] data) {
// distinct rows which contain max values
HashSet<int> result = new HashSet<int>();
// for each column we find rows that contain max values
for (int c = 0; c < data.GetLength(1); ++c) {
// max value so far
int max = data[0, c];
// List - we can have several rows with max value
List<int> maxRows = new List<int>() {0};
for (int r = 1; r < data.GetLength(0); ++r)
if (data[r, c] == max)
maxRows.Add(r);
else if (data[r, c] > max) {
maxRows.Clear();
maxRows.Add(max = data[r, c]);
}
foreach (int item in maxRows)
result.Add(item);
}
// let's return ordered rows - OrderBy
return result
.OrderBy(row => row)
.ToArray();
}
您可以使用HashSet<T>
来存储索引的唯一值。
GreatestNumberIndexes
方法查找当前列的最大值,然后添加结果 HashSet 的索引。 您也可以执行ToArray()
将索引作为数组获取。
这是代码:
private static HashSet<int> GreatestNumberIndexes(int[,] matrix,
int rows, int cols)
{
var indexes = new HashSet<int>();
for (var i = 0; i < cols; i++)
{
var max = int.MinValue;
for (int j = 0; j < rows; j++)
if (matrix[j, i] > max)
max = matrix[j, i];
for (int j = 0; j < rows; j++)
if (matrix[j, i] == max)
indexes.Add(j);
}
return indexes;
}
不是最优雅的解决方案,但:
int[,] matrix = new int[,]
{
{8, 4, 6, 6, 6, 6, 6, 6},
{7, 5, 7, 6, 6, 6, 6, 5},
{6, 6, 6, 5, 5, 5, 5, 6},
{8, 6, 8, 7, 7, 7, 7, 6},
{8, 6, 6, 6, 6, 6, 6, 6},
{8, 6, 6, 6, 6, 6, 6, 1}
};
HashSet<int> indicesOfMaxNumbers = new HashSet<int>();
for (int col = 0; col < matrix.GetLength(1); col++)
{
int curMax = matrix[0, col];
for (int row = 1; row < matrix.GetLength(0); row++)
{
if (curMax <= matrix[row, col])
{
curMax = matrix[row, col];
}
}
for (int row = 0; row < matrix.GetLength(0); row++)
{
if (curMax == matrix[row, col])
{
indicesOfMaxNumbers.Add(row);
}
}
}
indicesOfMaxNumbers.Sort();
Console.WriteLine(string.Join(", ", indicesOfMaxNumbers));
我在每一列中找到最大的元素,然后插入索引(如果尚未插入)。
PS你可以用它来优化它,因为我100%肯定有更好的解决方案
// init your example of rows
var matrixXY = new List<List<int>>
{
new List<int>{8, 4, 6, 6, 6, 6, 6, 6},
new List<int>{7, 5, 7, 6, 6, 6, 6, 5},
new List<int>{6, 6, 6, 5, 5, 5, 5, 6},
new List<int>{8, 6, 8, 7, 7, 7, 7, 6},
new List<int>{8, 6, 6, 6, 6, 6, 6, 6},
new List<int>{8, 6, 6, 6, 6, 6, 6, 1}
};
// turn it around for easier management
var matrixYX = new List<List<int>>();
for (int y = 0; y < matrixXY[0].Count; y++)
{
matrixYX.Add(new List<int>());
for (int x = 0; x < matrixXY.Count; x++)
{
matrixYX[y].Add(matrixXY[x][y]);
}
}
// get index of each max number per column
var indexGroups = matrixYX.Select(values =>
{
var maxValue = values.Max();
return values
.Select((value, i) => (Value: value, Index: i + 1))
.Where(tuple => tuple.Value == maxValue)
.Select(tuple => tuple.Index);
});
// pass all indexes into one array
var result = indexGroups
.SelectMany(indexes => indexes)
.Distinct();
因为总是有人为这些事情发布 LINQ 答案..
matrix.Cast<int>()
.Select((v, i) => new { R = i/matrix.GetLength(1), C = i%matrix.GetLength(1), V = v })
.GroupBy(rcv => rcv.C, rcv => rcv, (k, g) => g.OrderByDescending(rcv => rcv.V))
.SelectMany(g => g.TakeWhile(rcv => rcv.V == g.First().V), (g, rcv) => rcv.R)
.Distinct()
让我们通过go来学习一下吧。 我不确定我会在 prod 中使用它,但它作为一种思考练习很有趣,我在这里展示它是为了学习和好奇。
看一眼就判断你是否理解; 如果您和您团队中的其他人能够理解它并且它被测试为比非 LINQ 解决方案(我怀疑它会)更有效,那么很好..
..但请避免使用“诡计”的代码,但需要附带文档注释以供任何人理解。
为免生疑问,我发布此答案是因为它可以替代其他非常相似的答案,并且它为 LINQ 的一些不太常用的方面提供了很好的教育机会,因此我认为您会从中学到一些东西,但我真的认为你应该在你的生产系统中使用 ndogac 的答案..
N 维 arrays 的一个有用方面是您可以枚举它们,就好像它们是一维一样。 在这个 2D 的情况下,如果你要枚举它,你会得到第一行的所有项目,然后是第二行的所有项目:
foreach(int n in matrix) ....
8 4 6 6 6 6 6 6 7 5 7 6 6 6 6 5 6 6 6 5 5 5 5 6 8 6 8 7 7 7 7 6 8 6 6 6 6 6 6 6 8 6 6 6 6 6 6 1
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
first row second row
Now, 2D arrays don't implement IEnumerable<T>
so we can't straight call .Select
style LINQ extensions on them but you can get the same effect with the Cast<T>
operator, which effectively does a foreach(int v in array) yield return v;
在这种情况下,它为我们提供了一个可以使用的int
的单个可枚举 stream 。
我们希望按列与他们合作。
我们可以使用Select
方法计算列和行,该方法为我们提供了项目的索引以及项目:
.Select((v, i) => new { R = i/matrix.GetLength(1), C = i%matrix.GetLength(1), V = v })
v
是项目, i
是它所在的索引。 行R
由索引除以行长度给出:从索引 0 到 7,全部除以 8,为 0。从索引 8 到 15,除以 8,为 1 等。列C
由模给出又名上述除法的其余部分
这将输出具有 R C 和 V 属性的匿名类型,适当地给出行、列和值。 这是馈入...
.GroupBy(rcv => rcv.C, (k, g) => g.OrderByDescending(rcv => rcv.V))
这种形式的 GroupBy 很少使用,这里介绍的概念上等同于:
.GroupBy(rcv => rcv.C)
.Select(g => g.OrderByDescending(rcv => rcv.V))
它将按列分组,因为我们想将 stream 划分为“列表列表”,其中同一列的所有值都是可比较的,因此我们可以在该列中找到该值的最大值。
我们可以使用一些策略来获取最大值的行索引,例如:
这个解决方案使用了第二种,只是因为 TakeWhile 不经常使用,而且这是一个学术练习。 在这个初步步骤中,我们对列进行排序,使最大值接近顶部。 请记住,我们确实知道 R 中的行索引,因此我们将行按原始顺序排序并不重要
.SelectMany(g => g.TakeWhile(rcv => rcv.V == g.First().V), (g, rcv) => rcv.R)
SelectMany 是另一个不太常用的构造,这种形式可能更是如此。 第二个论点再次只是一个简短的形式:
.SelectMany(g => g.TakeWhile(rcv => rcv.V == g.First().V))
.Select(rcv => rcv.R)
SelectMany 是一个解组操作:它需要我们的 8 个列表,每个列表包含 6 个 object,每个列表是 GroupBy 给我们的,然后再次将其解包为最多 48 个对象。
SelectMany 期望得到一个集合作为它的第一个参数,这里我们给它减少列中的 6 个项目:我们将TakeWhile
的数字与第一个数字相同。 这里一遍又一遍地计算第一个效率有点低,但它比一遍又一遍地计算 Max 效率更高。 你可以说g => { var f = g.First().V; return g.TakeWhile(rcv => rcv.V == f) ]
g => { var f = g.First().V; return g.TakeWhile(rcv => rcv.V == f) ]
只计算第一个
因此,该组中的 output 是 6 个 RCV 的有序列表,V 的降序排列,这成为我们的“组” g
。 然后我们将它减少到与第一个 V 相同的 V(根据降序排序的定义,它必须是最大值),这意味着我们从第一列中得到 4 个 RCV(那些 V 为 8 的)
SelectMany 将访问每一列,从每个组中获取最大 RCV,并根据第二个参数(g, rcv) => rcv.R
发出它们,它只提取行索引 R,并在其中添加 1(您在其他的建议)
最终结果是行索引的 stream 中包含重复项,因此我们使用Distinct()
删除它们
脚注,如果您想要通过“值等于最大值”起作用的东西,它可能看起来像:
matrix.Cast<int>()
.Select((v, i) => new { R = i/matrix.GetLength(1), C = i%matrix.GetLength(1), V = v })
.GroupBy(rcv => rcv.C, (g, rcv) => new { G = g, M = g.Max(rcv => rcv.V) })
.SelectMany(gwm => gwm.G.Where(rcv => rcv.V == gwm.M), (g, rcv) => rcv.R + 1))
.Distinct()
简而言之,GroupBy 输出一个新的匿名类型,其中包括组(值的列)和其中的最大值。 SelectMany 将依赖于最大值,因此我们不想一遍又一遍地计算它)。 GroupBy 生成一个“最大组”,我在 SelectMany 中将其别名为gwm
。 SelectMany,只为那些具有最大值的人做一个Where
..
..但除此之外它和以前一样
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.