在C#中查找行元素之间的差异

时间:2011-11-01 12:05:41

标签: c# arrays list

我是这个页面的新手,也是编程新手。
让我提出我的问题。 我有一个数组让我们说

1 2 3

4 5 6

7 8 9 

3 2 1

我想要做的是计算每一行所有元素之间的差异。

{Math.Abs(1-2)=1

Math.Abs (2-3)=1

Math.Abs (1-3)=2}

表示第一行。接下来我想找到每一行的平均值(在第一行(1 + 1 + 2)/ 3中),最后保持行的平均值最小。

最有效的方法是什么?(我认为perphaps LINQ可以工作,但我不知道如何正确使用LINQ)。 任何帮助,将不胜感激。 谢谢大家!!!!

编辑: 谢谢大家的答案......真的很有用,帮助我了解我应该如何处理我的问题。我看到大多数人都推荐使用List。所以这给我带来了另一个问题(记住很少的编程知识)如何将int [,]数组转换为List,这是可能的吗?我应该首先将int [,]转换为int [] []然后转换为List吗? 再一次感谢您的回答和时间。

我创建了以下函数,用于将2d数组转换为List ..但它似乎无法正常工作..任何帮助都会真正受到赞赏..

 public static List<int[]> GetMyNumbers(int[,] result)
    {

        int[,] res = result;

        int length = res.GetUpperBound(0) + 1;
        int width = res.GetUpperBound(1) + 1;
        int[] rows = new int[width];
        List<int[]> numberArrays = new List<int[]>();

        for (int i = 0; i < result.Length / width; i++)
        {
            for (int k = 0; k < width; k++)
            {
                rows[k] = res[i, k];
                Console.Write(rows[k]);
            }
            Console.WriteLine();
            numberArrays.Add(rows);//this doesn't fill the list properly..It adds to all list items the last row of the 2d array

        }

        return numberArrays;


    }

8 个答案:

答案 0 :(得分:2)

这非常粗糙,但希望你可以从中获取。基本上,它将您的锯齿状数组转换为数组列表,然后以单独的方法计算平均值,并按平均值排序结果并取一个。

值得注意的是,我的解决方案总是试图存储差异的正值(因为这似乎是你正在做的事情),即代替1和3给出-2它给出了2.

我确信有一种更简洁的方法来创建这个解决方案,但这是我现在能想到的最好的方法。

static void Main(string[] args)
        {
            int[][] multi = new int[3][];
            multi[0] = new int[3] { 1, 2, 3 };
            multi[1] = new int[3] { 5, 10, 20 };
            multi[2] = new int[3] { 3, 4, 8 };
            List<int[]> t = multi.ToList();
            List<int[]> avg = t.OrderBy(x => GetAvgDifference(x)).Take(1).ToList();
        }

        public static double GetAvgDifference(int[] arr)
        {
            List<int> differences = new List<int>();
            for (int i = 0; i < arr.Length; i++)
            {
                for (int j = i; j < arr.Length; j++)
                {
                    int difference = arr[i] - arr[j];

                    if (difference < 1)
                    {
                        differences.Add(difference * -1);
                    }
                    else
                    {
                        differences.Add(difference);
                    }
                }
            }

            return differences.Average();
        }

答案 1 :(得分:2)

您可以在只有一行的数组上使用这样的LINQ:

int[] tab = { 1, 2, 3 };
var tuples = tab.Select((number, index) => new Tuple<int, int>(index, number));
var average = tuples.SelectMany(t => tuples.Where(current => current.Item1 > t.Item1), (t1, t2) => Math.Abs(t1.Item2 - t2.Item2)).Average();

您只需将相同的内容应用于数组的所有行,然后使用Min()扩展方法。

答案 2 :(得分:1)

如果我要解决这个问题,我会改变数据的存储方式。

首先,我将创建一个名为myNumbers(或其他)的新类,此类必须包含一个整数数组和一个名为average的属性,仅使用get方法(您不希望能够手动更改此值。也可以创建一个构造函数,它接受在创建类的新实例时要使用的整数数组。(这个新类代表你当前拥有的数组中的1行)

你的名为average的属性将是一个int,它将遍历数组并计算平均值然后返回它。

http://msdn.microsoft.com/en-us/library/aa288470(v=vs.71).aspx C#属性教程。

现在在您的主代码中,您想要删除数组,而是创建一个List并使用myNumbers类的新实例填充它。

现在你所要做的就是为每个循环创建一个并遍历列表,你可以检查列表中每个项目的平均属性以获得平均值,或者你可以完全忽略循环并使用LINQ来选择最高价值

http://msdn.microsoft.com/en-us/library/bb383799(v=vs.90).aspx Linq教程(网上还有更多内容)

我认为上述方法最适合您的需求,因为您需要存储平均值等。它还为您提供了类/属性/循环/列表等的练习,因为您不熟悉编程。

如果你有一些代码并且还在努力,请在此处更新您的帖子,我们会尽力提供帮助。我想我会在没有代码的情况下回答这个问题,所以至少你可以自己动手做等等。

答案 3 :(得分:1)

试试这个

    var rows = new List<List<int>>(){
            new List<int>(){1, 2, 3},
            new List<int>(){4, 5, 6},
            new List<int>(){7, 8, 9},
            new List<int>(){3, 2, 1}};

    var averages = new List<double>();
    foreach(var list in rows)
    {
        var diffs = new List<int>();
        for (int i = 0; i < list.Count - 1; i++)
            for (int j = i+1; j < list.Count; j++)
                diffs.Add(Math.Abs(list[i]-list[j]));
        averages.Add(diffs.Average());
    }
    averages.ForEach(i=>Console.WriteLine(i));
    Console.WriteLine("Minimum average is " + averages.Min());

所有序列的方式都有所不同,因此在本例中,所有平均值均为1.3333

答案 4 :(得分:1)

这是你正在寻找的东西。不,我没有测试代码以确保它是100%正确的,但至少应该让你朝着正确的方向前进。

  // Look, a two dimensional version.
  int[][] numberArray = GetMyNumbers();

  // Placeholder for the lowest averge / corresponding index.
  double lowestAvg = double.MaxValue;
  int lowestIndex = -1;

  for (int rowIndex = 0; rowIndex < numberArray.Length; rowIndex++)
  {

    {
      int[] row = numberArray[rowIndex];
      int n = row.Length;
      int[] diffs = new int[(n * n) - n];

      // Get all of the differences.
      int count = 0;
      for (int i = 0; i < n; i++)
      {
        for (int j = i + 1; j < n; j++)
        {
          diffs[count] = Math.Abs(row[i] - row[j]);
          count++;
        }
      }

      // Average them..
      double sum = 0;
      for (int i = 0; i < diffs.Length; i++)
      {
        sum += diffs[i];
      }
      double avg = sum / diffs.Length;

      // Compare to the lowest value, making note of a new low.
      if (avg < lowestAvg)
      {
        lowestAvg = avg;
        lowestIndex = rowIndex;
      }
    }

  }

  // Now that we are here, we know which index has the lowest average of differences.
  // Do whatever you want with it.
  int[] TheAnswer = numberArray[lowestIndex];

答案 5 :(得分:1)

如果性能真的很重要,请考虑使用flat int数组 存储您的行(您没有List<int>的内存开销)。 然后通过递增迭代平面数组 您的当前索引按行长度计算,然后计算平均值 当前行。

这是一个小例子:

int rowLen = 3;
int numberOfRows = 3;
int[] rowValues = new int[rowLen * numberOfRows];

float[] avgs = new float[numberOfRows];

// First row
rowValues[0] = 1;
rowValues[1] = 2;
rowValues[2] = 3;

// Second row
rowValues[3] = 6;
rowValues[4] = 5;
rowValues[5] = 6;

// Third row
rowValues[6] = 7;
rowValues[7] = 8;
rowValues[8] = 9;

float currMinAvg = float.MaxValue;
int minIdx = -1;
int currRow = 0; 
for (int i = 0; i <= numberOfRows * rowLen - rowLen; i += rowLen)
{    
  avgs[currRow] = 0;
  int c = 0;
  for (int k = i; k < i + rowLen-1; k++)
  {
    for (int p = k + 1; p < i + rowLen; p++)
    {
      c++;
      //Console.Out.WriteLine("calc: rowValues[{0}] - rowValues[{1}]", k, p);
      avgs[currRow] += Math.Abs(rowValues[k] - rowValues[p]);
    }
  }

  //Console.Out.WriteLine(avgs[currRow]);
  avgs[currRow] /= c;

  if (avgs[currRow] < currMinAvg)
  {
    minIdx = i;
    currMinAvg = avgs[currRow];
  }
  currRow++;
}

Console.Out.WriteLine("Min row indexs: {0}, min average = {1}", minIdx, currMinAvg);

请注意,上面的代码针对性能进行了优化。它显然伤害了可读性

希望,这有帮助。

答案 6 :(得分:1)

这里有一些带有一些注释的代码,我做了很奇怪的事情。我想你已经有了很多有趣的答案,但我没有看到任何简单明了的东西,所以这是我的尝试。

static void Main(string[] args)
{
    // quickest way to initialize your input
    var input = new int[][]{
        new int[]{1, 2, 3},
        new int[]{4, 5, 6},
        new int[]{7, 8, 9},
        new int[]{3, 2, 1}
    };

    /* to get the average,
     * 1. add up all the differences
     * 2. divide by m choose 2 where m is the length of a row
     */

    // helpful factorial functoid
    Func<int, int> factorial = null;
    factorial = (n => (n > 1) ? n * factorial(n - 1) : 1);
    var mChoose2 = factorial(input[0].Length) / (2 * factorial(input[0].Length - 2));

    var getAverageOfDifferencesFunctoid = new Func<int[], double>(
        row => row.Select(
            (number1, indexInRow1) => row.Select(
                (number2, indexInRow2) => indexInRow2 > indexInRow1 ? Math.Abs(number1 - number2) : 0
                // add up all the differences for number1 with the rest of the array
            ).Sum()
        // add up all the sums of all the differences
        ).Sum()
        // divide by the number of differences
        / (double)mChoose2
    );

    // use the functoid defined above to calculate the average of differences for each row and pick the minimum
    Console.WriteLine(input.Select(row => getAverageOfDifferencesFunctoid(row)).Min());
}

答案 7 :(得分:1)

double[,] A = { { 1, 2, 3 }, { 4, 5, 6 } , { ... } ... };
// Initialize array of averages
double[] R = new double[N] // N is number of rows
// Calculate averages for each row
for(int i=0; i<N; i++)
{
    R[i] = (Math.Abs(A[i,0]-A[i,1])+Math.Abs(A[i,1]-A[i,2])+Math.Abs(A[i,2]-A[i,0]))/3;
}
// Find the best value
double R_min = R.Max();
// Find the index where values equals the min.
int k = R.Select((r, i) => r == R_min ? i : N).Min();
// Now A[k,*] contains the values you want to keep.