繁体   English   中英

c# 在二维数组中查找特定数字的行索引

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM