简体   繁体   中英

Comparing an element in a matrix with the following ones

Let's say I have a matrix with 3 lines and 3 columns.

How can I compare each element with the elements after it?

Let's say for this matrix:

0 1 2
3 4 5
6 7 8

I want to compare 0 with all of them, 1 with 2, 3, 4, 5, 6, 7, 8; 2 with 3, 4, 5, 6, 7, 8 and so on.

How can this be achieved? I was thinking about something like this:

int c = 0;
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            for (int p = 0; p < 4; p++)
            {
                for (int t = 0; t < 4; t++)
                {
                    if (a[i][j] > a[p][t]) //comparison
                    {
                        c++; 
                    }
                }
            }
        }
    }

But it is not working and I know why, but I don't really know how to fix it.

Each element gets compared with all the elements in the matrix. For my result, each element has to be compared with everything which follows it. If it was a simple array, it would've looked like this:

for (int i = 0; i < length-1; i++)
    {
        for (int j = i+1; j < length; j++)
        {
            if (a[i][j] > a[p][t]) //comparison
            {
                c++;
            }
        }
    }

but how would this algorithm be replicated on a matrix?

Thanks.

Your actual problem is the inner loops need to start at least at the index of the outer loops + 1 also your ranges are wrong;

However, this is probably conceptually easier if you converted it to a 1d array. There are many ways to do this, though most will be at the cost of an allocation. However, on saying that, because of the way caching works on modern CPU's and the resulting JIT'ed code the performance of each will likely be surprising (benchmarks included).

Given

public static IEnumerable<T> Iterate<T>(T[,] source)
{
    foreach (var item in source)
       yield return item;
}

private int Enumerate(int[,] array)
{
   var c = 0;
   var items = Iterate(array).ToArray();
   for (var i = 0; i < items.Length; i++)
   for (var j = i + 1; j < items.Length; j++)
      if (items[i] > items[j]) c++;
   return c;
}

Usage

var array = new int[,]
{
   {0, 1, 2},
   {3, 4, 5},
   {6, 7, 8}
};
 
var c = Enumerate(array);

Console.WriteLine(c);

Other ways

Cast instead of iteration (allocation)

private int EnumerateCast(int[,] array)
{
   var c = 0;
   var items = array.Cast<int>().ToArray();
   for (var i = 0; i < items.Length; i++)
   for (var j = i + 1; j < items.Length; j++)
      if (items[i] > items[j]) c++;
   return c;
}

Fixed (no allocations)

private unsafe int Fixed(int[,] array)
{
   var c = 0;
   fixed (int* p = array)
      for (var i = 0; i < array.Length; i++)
      for (var j = i + 1; j < array.Length; j++)
         if (p[i] > p[j]) c++;
   return c;
}

Fixed ReadOnlySpan (no allocations)

private unsafe int FixedSpan(int[,] array)
{
   var c = 0;
   fixed (int* p = array)
   {
      var span = new ReadOnlySpan<int>(p,array.Length);
      for (var i = 0; i < array.Length; i++)
      for (var j = i + 1; j < array.Length; j++)
         if (span[i] > span[j]) c++;
      return c;
   }
}

Block copy (allocation)

private int Copy(int[,] array)
{
   var c = 0;
   int[] data = new int[array.Length];
   Buffer.BlockCopy(data, 0, data, 0, data.Length);
   for (var i = 0; i < data.Length; i++)
   for (var j = i + 1; j < data.Length; j++)
      if (data[i] > data[j]) c++;
   return c;
}

Branch and mod (no allocations)

private int Mod(int[,] array)
{
   var c = 0;
   for (int i = 0; i < array.GetLength(0); i++)
   for (int j = 0; j < array.GetLength(1); j++)
   for (int p = i; p < array.GetLength(0); p++)
   for (int t = (p == i ? j + 1 : 0); t < array.GetLength(1); t++)
      if (array[i, j] > array[p, t]) c++;
   return c;
}

Benchmarks

Environment

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.18363.1256 (1909/November2018Update/19H2)
AMD Ryzen 9 3900X, 1 CPU, 24 logical and 12 physical cores
.NET Core SDK=5.0.101
  [Host]        : .NET Core 5.0.1 (CoreCLR 5.0.120.57516, CoreFX 5.0.120.57516), X64 RyuJIT
  .NET Core 5.0 : .NET Core 5.0.1 (CoreCLR 5.0.120.57516, CoreFX 5.0.120.57516), X64 RyuJIT

Job=.NET Core 5.0  Runtime=.NET Core 5.0

Results

Method N Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
FixedSpan 10 4.381 us 0.0621 us 0.0581 us - - - -
Fixed 10 4.421 us 0.0540 us 0.0505 us - - - -
Enumerate 10 5.796 us 0.0525 us 0.0491 us 0.1450 - - 1224 B
Cast 10 12.083 us 0.0322 us 0.0251 us 0.4272 - - 3688 B
Copy 10 3.068 us 0.0346 us 0.0307 us 0.0496 - - 424 B
Mod 10 20.588 us 0.0616 us 0.0577 us - - - -
Method N Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
FixedSpan 100 110,439.837 us 189.7165 us 177.4610 us - - - 248 B
Fixed 100 118,407.023 us 406.6628 us 380.3926 us - - - 248 B
Enumerate 100 114,296.573 us 560.1114 us 523.9286 us - - - 106504 B
Cast 100 109,265.053 us 273.7071 us 256.0258 us - - - 346587 B
Copy 100 37,772.051 us 106.2733 us 94.2085 us - - - 40024 B
Mod 100 294,801.000 us 628.9780 us 588.3464 us - - - 668 B

Benchmark Code

[SimpleJob(RuntimeMoniker.NetCoreApp50)]
[MemoryDiagnoser]
public class Tester
{
   private int[,] _data;


   [Params(10, 100)] public int N;

   [GlobalSetup]
   public void GlobalSetup()
   {
      var rnd = new Random(32);
      _data = new int[N, N];
      for (var i = 0; i < N; i++)
      for (var j = 0; j < N; j++)
         _data[i, j] = rnd.Next(1, N);


   }

   public static IEnumerable<T> Iterate<T>(T[,] source)
   {
      foreach (var item in source)
         yield return item;
   }



   [Benchmark]
   public unsafe int FixedSpan() => FixedSpan(_data);

   private unsafe int FixedSpan(int[,] array)
   {
      var c = 0;
      fixed (int* p = array)
      {
         var span = new ReadOnlySpan<int>(p, array.Length);
         for (var i = 0; i < array.Length; i++)
         for (var j = i + 1; j < array.Length; j++)
            if (span[i] > span[j])
               c++;

         return c;
      }
   }

   [Benchmark]
   public unsafe int Fixed() => Fixed(_data);

   private unsafe int Fixed(int[,] array)
   {
      var c = 0;
      fixed (int* p = array)
         for (var i = 0; i < array.Length; i++)
         for (var j = i + 1; j < array.Length; j++)
            if (p[i] > p[j])
               c++;
      return c;
   }

   [Benchmark]
   public int Enumerate() => Enumerate(_data);

   private int Enumerate(int[,] array)
   {
      var c = 0;
      var items = Iterate(array).ToArray();
      for (var i = 0; i < items.Length; i++)
      for (var j = i + 1; j < items.Length; j++)
         if (items[i] > items[j])
            c++;
      return c;
   }

   [Benchmark]
   public int EnumerateCast() => EnumerateCast(_data);

   private int EnumerateCast(int[,] array)
   {
      var c = 0;
      var items = array.Cast<int>().ToArray();
      for (var i = 0; i < items.Length; i++)
      for (var j = i + 1; j < items.Length; j++)
         if (items[i] > items[j])
            c++;
      return c;
   }

   [Benchmark]
   public int Copy() => Copy(_data);

   private int Copy(int[,] array)
   {
      var c = 0;
      var data = new int[array.Length];
      Buffer.BlockCopy(data, 0, data, 0, data.Length);
      for (var i = 0; i < data.Length; i++)
      for (var j = i + 1; j < data.Length; j++)
         if (data[i] > data[j])
            c++;
      return c;
   }

   [Benchmark]
   public int Mod() => Mod(_data);

   private int Mod(int[,] array)
   {
      var c = 0;
      for (int i = 0; i < array.GetLength(0); i++)
      for (int j = 0; j < array.GetLength(1); j++)
      for (int p = i; p < array.GetLength(0); p++)
      for (int t = (p == i ? j + 1 : 0); t < array.GetLength(1); t++)
         if (array[i, j] > array[p, t]) //comparison
            c++;
      return c;
   }

   private static void Main(string[] args)
   {
      BenchmarkRunner.Run<Tester>();

   }
}

The easiest thing to do would be converting the matrix into an array and use the last code you showed.

However, if you really want to use the matrix, you need to adjust your first code so p starts as i and t starts as j + 1 if p == i and as 0 otherwise.

int[,] a = new int[3,3] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };

int c = 0;
for (int i = 0; i < 3; i++)
{
    for (int j = 0; j < 3; j++)
    {
        for (int p = i; p < 3; p++)
        {
            for (int t = (p == i ? j + 1 : 0); t < 3; t++)
            {
                if (a[i,j] > a[p,t]) //comparison
                {
                    c++;
                }
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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