Sum of all numbers in a multi-dimensional array - c#

I'm currently learning C# and running into some trouble with multi dimension array.
I can't seem to figure out how to find the sum of all the elements in the array. E.g
int[,] array = { { 52, 76, 65 }, { 98, 87, 93 }, { 43, 77, 62 }, { 72, 73, 74 } };
So the sum should be:
52 + 76 + 65 + 98 + ...
I have tried to use the for loop but that just give me the sum of each array in dimension 1. E.g
private int[,] array = { { 52, 76, 33}, { 98, 87, 93 }, { 43, 77, 62 }, { 72, 73, 74 } };
public void ArraySum()
{
double sum;
for (int i = 0; i < array.GetLength(0); i++)
{
sum = 0;
for (int j = 0; j < array.GetLength(1); j++)
sum += array[i, j];
Console.WriteLine("The sums are for the array {0} is {1}: ", i, sum);
}
}
Any ideas?

The other answer pointed out what's wrong with your code. Here's a short alternative to your loops using LINQ:
int[,] array = { { 52, 76, 65 }, { 98, 87, 93 }, { 43, 77, 62 }, { 72, 73, 74 } };
int sum = array.Cast<int>().Sum();
The Cast is used to convert the multidimensional array to an IEnumerable<int> which then allows you to use the Sum extension method.

Since you're just learning and playing around anyway, you could use a List<int<int>> to store your values instead of a 2-dimensional array, like this:
var array = new List<List<int>>
{
new List<int> {52, 76, 65},
new List<int> {98, 87, 93},
new List<int> {43, 77, 62},
new List<int> {72, 73, 74}
};
Then you could easily use LINQ to get your sum:
var sum = array.SelectMany(x => x).Sum();
If you haven't heard of it yet, you can learn more about LINQ here.
Basically, SelectMany() flattens your multiple lists into one list, and then Sum() just adds them all up.

Simply move the line sum = 0; out of the first loop:
private int[,] array = { { 52, 76, 33}, { 98, 87, 93 }, { 43, 77, 62 }, { 72, 73, 74 } };
public void ArraySum()
{
int sum = 0;
for (int i = 0; i < array.GetLength(0); i++)
{
for (int j = 0; j < array.GetLength(1); j++)
sum += array[i, j];
}
Console.WriteLine("The sum for the whole array is {0}: ", sum);
}
In your code the sum is reset to 0 for each sub-array.
Edit
Since the array contains int values, consider to declare the sum variable as int instead of double.

If all you want is the sum of the entire array, then
private static int[,] array = { { 52, 76, 33}, { 98, 87, 93 }, { 43, 77, 62 }, { 72, 73, 74 } };
public static void Main()
{
double sum = 0;
for (int i = 0; i < array.GetLength(0); i++)
{
for (int j = 0; j < array.GetLength(1); j++)
sum += array[i, j];
}
Console.WriteLine("The sum for the array is {0}: ", sum);
}

Related

Print X for value of Array

I'm trying to print "x" for the value within the array for example the integer 32 would print 32 x's but I'm not sure how to go about doing so.
Any help or pointers on what to do would be great have looked around but can't seem to find anything that helps me without over complicating it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Histogram
{
class Program
{
static void Main(string[] args)
{
string output = "";
int[] x;
x = new int[18];
int[] y = { 32, 27, 64, 18, 95, 14, 90, 70, 60, 37, 17, 56, 99, 34, 75, 36, 12, 8, 100, 77 };
const int ARRAY_SIZE = 18;
int[] z;
z = new int[ARRAY_SIZE];
for (int i = 0; i < z.Length; i++)
z[i] = 2 * i;
Console.WriteLine("Element\t \tValue\t \tHistogram\t\t\n");
for (int i = 0; i < ARRAY_SIZE; i++)
{
output += i + "\t\t" + y[i] + "\t\t" + y[i] + "\t\t" + "\n";
}
Console.WriteLine(output);
Console.ReadKey();
}
}
}
What you are looking for is already built into String class. It has a constructor
to create a string of repeating chars for any length. No need for String Builder or any extra loops, that would be over complicated.
static void Main(string[] args)
{
string output = "";
const int ARRAY_SIZE = 18;
int[] x = new int[ARRAY_SIZE];
int[] z = new int[ARRAY_SIZE];
int[] y = { 32, 27, 64, 18, 95, 14, 90, 70, 60, 37, 17, 56, 99, 34, 75, 36, 12, 8, 100, 77 };
for (int i = 0; i < z.Length; i++)
z[i] = 2 * i;
Console.WriteLine("Element\t \tValue\t \tHistogram\t\t\n");
for (int i = 0; i < ARRAY_SIZE; i++)
{
string bar = new string('X', y[i]);
output += i + "\t\t" + y[i] + "\t\t" + bar + "\t\t" + "\n";
}
Console.WriteLine(output);
Console.ReadKey();
}
I was not entirely sure if I was following what you wanted to do but this piece of code may be something like what you were doing with your loops.
Used StringBuilder because it "doesn't create a new object in the memory but dynamically expands memory to accommodate the modified string"
using System;
using System.Text;
public class Program
{
public static void Main()
{
string output = "";
StringBuilder sb = new StringBuilder("x");
int[] y = { 32, 27, 64, 18, 95, 14, 90, 70, 60, 37, 17, 56, 99, 34, 75, 36, 12, 8, 100, 77 };
//used to determine how many elements in the y array to go through
const int ARRAY_SIZE = 5;
int[] z;
z = new int[ARRAY_SIZE];
for(int i=0; i< z.Length; i++){
if(sb.Length != y[i])
sb.Clear();
for(int j=0; j < y[i]; j++)
sb.Append("x");
output += i + "\t\t" + y[i] + "\t\t" + sb + "\t\t" + "\n";
//clear the string builder var for next set of x's
sb.Clear();
}
Console.WriteLine(output);
}
}
The easiest thing would probably be to put the cout statement into 2 for loops. The first one for the length of the Array you want to print and the second one for the Number that is at that place.
As an example (array is the name of your array and ARRAY_SIZE is the length):
for (int x = 0; x < ARRAY_SIZE; x++) {
for (int y = 0; y <= array[x]; y++) {
output += x + " ";
}
output += "\n";
}
I would use the PadRight method as #TaW suggested. I don't see any reason why you stored your result on the output variable, then printed it.
Please find my solution below(removed unnecessary codes) where I am printing immediately without a need to store anything in the memory:
static void Main(string[] args)
{
const char paddingChar = 'X';
const string tabs = "\t\t";
int[] y = { 32, 27, 64, 18, 95, 14, 90, 70, 60, 37, 17, 56, 99, 34, 75, 36, 12, 8, 100, 77 };
Console.WriteLine($"Element{tabs}Value{tabs}Histogram");
for (int i = 0; i < y.Length; i++)
{
Console.WriteLine($"{i}{tabs}{y[i]}{tabs}{"".PadRight(y[i], paddingChar)}");
}
Console.ReadKey();
}

Forming an array out of maximum value of one part of the two dimensional arrays

So, i have a two dimensional arrays like this :
double[,] tabel_nilai = new double[,]{{3500, 70, 10, 80, 3000, 36},
{4500, 90, 10, 60, 2500, 48 },
{4000, 80, 9, 90, 2000, 48 },
{4000, 70, 8, 50, 1500, 60 }};
and then, I want to form one dimensional array with the maximum value on the first column (3500, 4500, 4000 and 4000). But, minimum value on the other column.
I did this :
double[] pembagi = new double[kepentingan.Length];
for (int i = 0; i < produk.Length; i++)
{
for(int j=0; j < kriteria.Length; i++)
{
pembagi[i] = Math.Max(tabel_nilai[i,j],tabel_nilai[i,j]);
Console.WriteLine(pembagi);
}
}
but, failed miserably.
I would be very pleased if somebody can give me some logics on how to solve this problem. thanks
You can use LINQ in this case that probably gives the shortest and simplest code to solve this without explicit use of any nested loops.
double[,] tabel_nilai = new double[,]{ {3500, 70, 10, 80, 3000, 36},
{4500, 90, 10, 60, 2500, 48 },
{4000, 80, 9, 90, 2000, 48 },
{4000, 70, 8, 50, 1500, 60 }};
double[] oneDimensionalArray = tabel_nilai.Cast<double>().Select((x, i) => new { x, index = i / tabel_nilai.GetLength(1) })
.GroupBy(x=>x.index)
.Select(x=>x.Select(s=>s.x).ToList().Max())
.ToArray();
What it does is that it converts the 2D array into a list and then groups by each row and finally calculates Max value for that row. You can use it to get Min as well, just replace Max() with Min(). Additionally, it can help you do many other measures if you need using the same expression.
I hope it helps.
First you can use jagged arrays to get "slice" or row of rows.
Then using delegate you can apply function as per requirement, example below:
delegate double maxMin(IEnumerable<double> arr);
public static void GetData()
{
double[][] tableData = new double[][]{
new double[] {3500, 70, 10, 80, 3000, 36},
new double[] {4500, 90, 10, 60, 2500, 48 },
new double[] {4000, 80, 9, 90, 2000, 48 },
new double[] {4000, 70, 8, 50, 1500, 60 }
};
int length = tableData.Length;
double[] requiredValues = new double[length];
maxMin maxMinObj;
for (int i = 0; i < length; i++)
{
if (i == 0)
maxMinObj = x => x.Max();
else
maxMinObj = x => x.Min();
requiredValues[i] = maxMinObj(tableData[i]);
Console.WriteLine(requiredValues[i]);
}
}
Assuming alternating max/min for each column here is the correction to your code. Your code had multiple issues, so I'll just post the code with all the corrections:
using System;
public class Program
{
public static void Main()
{
double[,] tabel_nilai = new double[,]{ {3500, 70, 10, 80, 3000, 36},
{4500, 90, 10, 60, 2500, 48 },
{4000, 80, 9, 90, 2000, 48 },
{4000, 70, 8, 50, 1500, 60 }};
for (int j = tabel_nilai.GetLowerBound(1); j <= tabel_nilai.GetUpperBound(1); j++)
{
var seekingMax = ((j - tabel_nilai.GetLowerBound(1)) % 2) == 0;
var maxmin = tabel_nilai[0, j];
for(int i = tabel_nilai.GetLowerBound(0) + 1; i <= tabel_nilai.GetUpperBound(0); i++)
{
if (seekingMax)
{
maxmin = Math.Max(maxmin,tabel_nilai[i, j]);
}
else
{
maxmin = Math.Min(maxmin,tabel_nilai[i, j]);
}
}
Console.WriteLine("{0}: {1}", seekingMax ? "Max" : "Min", maxmin);
}
}
}

Multidimensional array column sorting

assume i create this code to generate the idv-th random number. But i have a difficulty in sorting the array depends on the last column.
let say the individual size is [idv, width] = [8,6]
and i want to sort all the row with column 6th... and i want to take the 4 top list in the array after it sorted. How can i implement this case to the code??
public static void population(double[,] individual, int width, int idv, Random rnd)
{
for (int i = 0; i < idv; i++)
{
Console.Write("individual {0} :\t", i+1);
for (int j = 0; j < width; j++)
{
individual[i, j] = Math.Round(rnd.NextDouble() * 10, 2);
Console.Write("{0} ", individual[i, j]);
}
Console.WriteLine("\n");
}
}
Thank you
I suggest you using jagged arrays double[][] instead of 2d ones double[,]. Jagged array is just an array of array which you can easily sort, filter, etc. usually with a help of Linq:
double[][] individual = new double[][] {
new double[] {81, 82, 83, 84, 85, 86},
new double[] {11, 12, 13, 14, 15, 16},
new double[] {41, 42, 43, 44, 45, 46},
new double[] {31, 32, 33, 34, 35, 36},
new double[] {51, 52, 53, 54, 55, 56},
new double[] {21, 22, 23, 24, 25, 26},
new double[] {61, 62, 63, 64, 65, 66},
new double[] {71, 72, 73, 74, 75, 76},
};
double[][] fragment = individual
.OrderBy(line => line[line.GetUpperBound(0)]) // by last column
.Take(4)
.ToArray();
One more Linq to test the results:
String test = String.Join(Environment.NewLine, fragment
.Select(line => String.Join("\t", line)));
Console.Write(test);
The result is
11 12 13 14 15 16
21 22 23 24 25 26
31 32 33 34 35 36
41 42 43 44 45 46
If you use multidimensional arrays, there's no easy way to work with them using LINQ, you'll need to rely on good old for.
static void Main ()
{
// Input array
double[,] u = {
{ 1, 9, 3 },
{ 0, 3, 4 },
{ 3, 4, 5 },
{ 3, 6, 8 },
{ 3, 5, 7 },
};
// Get dimension sizes, specify column to order by
int count = u.GetLength(0), length = u.GetLength(1), orderBy = 2;
// Result array
double[,] v = new double[count, length];
// Construct a list of indices to sort by
var indices = Enumerable.Range(0, count).OrderBy(i => u[i, orderBy]).ToList();
// Copy values from input to output array, based on these indices
for (int i = 0; i < count; i++)
for (int j = 0; j < length; j++)
v[i, j] = u[indices[i], j];
PrintArray(u);
Console.WriteLine();
PrintArray(v);
}
static void PrintArray (double[,] a)
{
for (int i = 0; i < a.GetLength(0); i++) {
for (int j = 0; j < a.GetLength(1); j++)
Console.Write(a[i, j]);
Console.WriteLine();
}
}
If you need only top 4 rows, you can add Take(4) before ToList() call and adjust result array creation and copying of values into it appropriately.
Multidimenional arrays are more efficient and use less memory, so if your arrays are big enough or you need to work with them faster, you may need to write a little more code and use multidimenional arrays instead of jagged arrays which are easier to work with.
For rectangular array [,] you can copy the desired column in a single-dimensional array together with indices, sort it, and then get rows with first 4 indices.
static IEnumerable<Tuple<int, double>> GetColumn(int columnIndex, double[,] a)
{
for (int i = a.GetLowerBound(0); i <= a.GetUpperBound(0); i++)
yield return Tuple.Create(i, a[i, columnIndex]);
}
double [,] data = ...;
var column = GetColumn(4, data);
var top4Indices = column.OrderBy(v => v.Second)
.Take(4)
.Select(v => v.First);
foreach (int i in top4Indices)
for (int j = data.GetLowerBound(1); j <= data.GetUpperBound(1); j++)
data[i, j]...

sorting many arrays according to a sorted index of an array C#

int[] a = {120, 60, 50, 40, 30, 20};
int[] b = {12, 29, 37, 85, 63, 11};
int[] c = {30, 23, 90 ,110, 21, 34};
Now i want to sort a and use its index to sort b and c
For eg:
sorted a = {20,30,40,50,60,120};
sorted b should be ={ 11,63,85,37,29,12};
and sorted c should be = { 34,21,110,90,23,30};
How to do it in C#
One option:
int[] a = {120, 60, 50, 40, 30, 20};
int[] b = {12, 29, 37, 85, 63, 11};
int[] c = {30, 23, 90 ,110, 21, 34};
var ordered = a.Select((item, index) =>
Tuple.Create(item, b[index], c[index]))
.OrderBy(tuple => tuple.Item1).ToArray();
a = ordered.Select(tuple => tuple.Item1).ToArray();
b = ordered.Select(tuple => tuple.Item2).ToArray();
c = ordered.Select(tuple => tuple.Item3).ToArray();
You could do it with a layer of indirection, like this:
Put the values 0, 1, 2, ..., N-1 into an int array, named indices, say.
Sort the array indices such that a[indices[i]] <= a[indices[i+1]] for all i. Your compare function will compare a[indices[Left]] with a[indices[Right]].
Access elements in the other arrays using the indirection: a[indices[i]] and so on.
You could make new copies of a, b and c if you wish, using the order defined by indicies. But you also have the option of not modifying the original arrays.
This option of not modifying the original arrays is quite interesting. It allows you have have multiple simultaneous orderings active in tandem.
Got bored so I tried to minimise the creation of new objects and sorting.
static void Main(string[] args)
{
int[] a = { 120, 60, 50, 40, 30, 20 };
int[] b = { 12, 29, 37, 85, 63, 11 };
int[] c = { 30, 23, 90, 110, 21, 34 };
var indexes = Enumerable.Range(0, a.Length).OrderBy(i => a[i]).ToArray();
var temp = new int[a.Length];
foreach (var arr in new[] { a, b, c })
{
for (int i = 0; i < a.Length; i++) temp[i] = arr[indexes[i]];
for (int i = 0; i < a.Length; i++) arr[i] = temp[i];
}
Console.WriteLine(String.Join(", ", a));
Console.WriteLine(String.Join(", ", b));
Console.WriteLine(String.Join(", ", c));
Console.ReadLine();
}
Not the best it could be (I'm sure you can get rid of the temp array somehow) - but a different solution nonetheless. I'd support sticking with the LINQesque solutions until performance becomes an issue.
You can use SortedList for this. SortedList sorts your items using a Key. Also it allows you
to add new items to your collection.
SortedList Class:
Represents a collection of key/value pairs that are sorted by the keys and are accessible by key and by index.
SortedList by MSDN
I suggest to use LINQ as Eli Arbel provided the answer.
But here is an other solution for those who don't know LINQ.
class Program
{
public static int get_key(int key , int [,] keylist)
{
for (int i = 0; i <= keylist.GetUpperBound(0); ++i)
{
if (keylist[i, 0] == key)
return keylist[i, 1];
}
return -1;
}
public static int[] Sort_by_index(int [] arr , int [] key , int [,] index_list)
{
int[] _out = new int[arr.Length];
for (int i = 0; i < key.Length; i++)
{
//Get key index
int key_index = get_key(key[i], index_list);
_out[i] = arr[key_index];
}
return _out;
}
static void Main(string[] args)
{
int[] a = { 120, 60, 50, 40, 30, 20 };
int[] b = { 12, 29, 37, 85, 63, 11 };
int[] c = { 30, 23, 90, 110, 21, 34 };
int[,] a_index = { { 120, 0 }, { 60, 1 }, { 50, 2 }, { 40, 3 }, { 30, 4 }, { 20, 5 } };
Array.Sort(a);
b =Sort_by_index(b, a, a_index);
c =Sort_by_index(c, a, a_index);
Console.WriteLine("Result A");
Console.WriteLine(string.Join(", ",a));
Console.WriteLine("Result B");
Console.WriteLine(string.Join(", ",b));
Console.WriteLine("Result C");
Console.WriteLine(string.Join(", ",c));
Console.ReadKey(false);
}
}

How to find a group of integers(N) amongst records, that contains 6 integers

I'm having problem with finding most common group of integers among int[x,6] array, where x <= 100000. Numbers are between 0 and 50.
eg input. (N = 2)
14 24 44 36 37 45 - here
01 02 06 24 33 44
10 17 34 40 44 45 - here
12 13 28 31 37 47
01 06 07 09 40 45
01 05 06 19 35 44
13 19 20 26 31 47
44 20 30 31 45 46 - here
02 04 14 23 30 34
27 30 41 42 44 49
03 06 15 27 37 48
output:
44, 45 (3) // appeared 3 times
Attached code I tried. Now I understand it doesn't work, but I was asked me to post it. I'm not just asking help without even trying.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace TotoLotek
{
class Program
{
static void Main(string[] args)
{
StreamReader czytnik = new StreamReader("dane_wejsciowe.txt");
List<int[]> lista = new List<int[]>();
string linia = "";
while ((linia = czytnik.ReadLine()) != null)
{
string[] numery = linia.Split(' ');
int[] tablica_intow = new int[6];
for (int i = 0; i < 6; i++)
{
tablica_intow[i] = int.Parse(numery[i]);
}
lista.Add(tablica_intow);
}
czytnik.Close();
int[] tablica = new int [50];
for (int i = 0; i< lista.Count(); i++)
{
for (int j = 0; j < 6; j++)
{
tablica[lista[i][j]]++;
}
}
int maks = tablica[0];
int maks_indeks = 0;
for (int i = 0; i < 50; i++)
{
if (tablica[i] > maks)
{
maks = tablica[i];
maks_indeks = i;
}
}
Console.Write("{0}({1}) ", maks_indeks, maks);
List<int[]> lista2 = new List<int[]>();
for (int i = 0; i < lista.Count(); i++)
{
for (int j = 0; j < 6; j++)
{
if (lista[i][j] == maks_indeks)
lista2.Add(lista[i]);
break;
}
}
int[] tablica2 = new int[50];
for (int i = 0; i < lista2.Count(); i++)
{
for (int j = 0; j < 6; j++)
{
tablica2[lista2[i][j]]++;
}
}
int maks2 = tablica2[0];
int maks_indeks2 = 0;
for (int i = 0; i < 50; i++)
{
if (tablica2[i] > maks2 && i != maks_indeks)
{
maks2 = tablica2[i];
maks_indeks2 = i;
}
}
Console.Write("{0}({1}) ", maks_indeks2, maks2);
int xdddd = 2;
}
}
}
Loop through the rows and all the numbers in each row. Pair each number with all higher numbers and count all combinations. When you are done you just sort the result on the count and take the highest:
int[][] numbers = {
new int[] { 14, 24, 44, 36, 37, 45 },
new int[] { 01, 02, 06, 24, 33, 44 },
new int[] { 10, 17, 34, 40, 44, 45 },
new int[] { 12, 13, 28, 31, 37, 47 },
new int[] { 01, 06, 07, 09, 40, 45 },
new int[] { 01, 05, 06, 19, 35, 44 },
new int[] { 13, 19, 20, 26, 31, 47 },
new int[] { 44, 20, 30, 31, 45, 46 },
new int[] { 02, 04, 14, 23, 30, 34 },
new int[] { 27, 30, 41, 42, 44, 49 },
new int[] { 03, 06, 15, 27, 37, 48 }
};
var count = new Dictionary<KeyValuePair<int, int>, int>();
foreach (int[] row in numbers) {
foreach (int i in row) {
foreach (int n in row.Where(n => n > i)) {
KeyValuePair<int, int> key = new KeyValuePair<int, int>(i, n);
if (count.ContainsKey(key)) {
count[key]++;
} else {
count.Add(key, 1);
}
}
}
}
KeyValuePair<KeyValuePair<int, int>, int> most =
count.ToList().OrderByDescending(n => n.Value).First();
Console.WriteLine("{0}, {1} ({2})", most.Key.Key, most.Key.Value, most.Value);
Output:
44, 45 (3)
NOW I HAVE IMPROVED MY ALGORITHM. NOW IT WORKS!!!!
class Program
{
static void Main(string[] args)
{
List<int[]> list = new List<int[]>();
list.Add(new int[] { 10, 20, 30, 40, 50});
list.Add(new int[] { 10, 20, 30, 40, 50 });
list.Add(new int[] { 10, 20, 30, 40, 50 });
list.Add(new int[] { 10, 20, 30, 40, 50 });
list.Add(new int[] { 10, 20, 30, 40, 50 });
// The N
int amountInCombination = 4;
Dictionary<String, int> dictionary = new Dictionary<String, int>();
foreach (int[] ints in list)
{
List<String> names = GetAllElemntCombinationsInRow(amountInCombination, ints);
int count = 0;
foreach (string name in names)
{
if (dictionary.TryGetValue(name, out count))
{
dictionary[name]++;
}
else
{
dictionary.Add(name, 1);
}
}
}
KeyValuePair<String, int> result = dictionary.OrderByDescending(e => e.Value).First();
Console.WriteLine("{0} ({1})", result.Key, result.Value);
//dictionary.OrderByDescending(e=>e.Value).First()
}
public static List<String> GetAllElemntCombinationsInRow(int amountInCombination, int[] row)
{
List<String> result = new List<string>();
List<String> tempUniq = new List<string>();
for (int i = 0; i < row.Count(); i++)
{
tempUniq = new List<string>();
if (amountInCombination != 1)
{
int[] temp = new int[row.Length-i-1];
Array.Copy(row,i+1, temp,0,row.Length-i-1);
tempUniq = GetAllElemntCombinationsInRow(amountInCombination - 1, temp);
}
else
{
result.Add(row[i].ToString());
}
if (tempUniq.Count != 0)
{
for (int j = 0; j < tempUniq.Count; j++)
{
result.Add(row[i].ToString() + "," + tempUniq[j]);
}
}
}
return result;
}
}
var input = new int[][]
{
new [] {14, 24, 44, 36, 37, 45},//- here
new [] {01, 02, 06, 24, 33, 44},
new [] {10, 17, 34, 40, 44, 45},//- here
new [] {12, 13, 28, 31, 37, 47},
new [] {01, 06, 07, 09, 40, 45},
new [] {01, 05, 06, 19, 35, 44},
new [] {13, 19, 20, 26, 31, 47},
new [] {44, 20, 30, 31, 45, 46},//- here
new [] {02, 04, 14, 23, 30, 34},
new [] {27, 30, 41, 42, 44, 49},
new [] {03, 06, 15, 27, 37, 48},
};
The implementation:
var matches = new List<int[]>();
for (int i = 0; i < input.Length; i++)
{
// Compare with all the next arrays
// "j = i + 1", to do not compare twice
for (int j = i + 1; j < input.Length; j++)
{
var match = input[i].Intersect(input[j]).ToArray();
if (match.Length > 1) // The smallest group contains 2 elements
{
matches.Add(match);
}
}
}
var comparer = new ArrayComparer<int>();
var mostCommon = matches
.GroupBy(p => p, comparer)
// Sort by frequency
.OrderByDescending(p => p.Count())
// Sort by the group's length
.ThenByDescending(p => p.Key.Count())
.FirstOrDefault();
The ArrayComparer<T> class:
public class ArrayComparer<T> : EqualityComparer<IEnumerable<T>>
{
public override bool Equals(IEnumerable<T> x, IEnumerable<T> y)
{
return x != null && y != null &&
(x == y || Enumerable.SequenceEqual(x,y));
}
public override int GetHashCode(IEnumerable<T> obj)
{
return obj.Sum(p => p.GetHashCode() + p.GetHashCode());
}
}
Display the result:
if (mostCommon != null)
{
Console.WriteLine("Most common: {{{0}}} ({1})",
string.Join(", ", mostCommon.Key), mostCommon.Count());
}
else
{
Console.WriteLine("Not found.");
}
Output:
Most common: {44, 45} (3)
Make an array of size X (possible numbers, so 50). Iterate through all numbers and increment each one to the appropriate index. Grab the highest N numbers out of the array (you know which number it is based on the index.
A more elegant solution might be required for large numbers of X.
int[][] numbers =
{
new[] {14, 24, 44, 36, 37, 45},
new[] {01, 02, 06, 24, 33, 44},
new[] {10, 17, 34, 40, 44, 45},
new[] {12, 13, 28, 31, 37, 47},
new[] {01, 06, 07, 09, 40, 45},
new[] {01, 05, 06, 19, 35, 44},
new[] {13, 19, 20, 26, 31, 47},
new[] {44, 20, 30, 31, 45, 46},
new[] {02, 04, 14, 23, 30, 34},
new[] {27, 30, 41, 42, 44, 49},
new[] {03, 06, 15, 27, 37, 48}
};
int[] counts = new int[50];
foreach (var rowOfNumbers in numbers)
{
foreach (var number in rowOfNumbers)
{
counts[number]++;
}
}
int[] top = new[] {0, 0};
for (int i = 0; i < counts.Length; i++)
{
if (counts[i] > top[0])
top[0] = i;
else if (counts[i] > top[1])
top[1] = i;
}
Could easily refactor to a method to be more robust.
var pairs = numbers.Select(x =>
{
List<KeyValuePair<int, IList<int>>> pairList = new List<KeyValuePair<int, IList<int>>>();
for (int i = 0; i <= 4; i++)
{
for (int j = i + 1; j <= 5; j++)
{
//Get the pair
var pair = new List<int> { x.Skip(i).First(), x.Skip(j).First() };
//Pair should be unique, so make the ID the sum
pairList.Add(new KeyValuePair<int, IList<int>>(pair.Sum(), pair));
}
}
return pairList;
}).SelectMany(x => x.Select(y => y.Value)).GroupBy(x => x, new PairComparer()).ToList();
int iHighest = pairs.Max(p => p.Count());
var highestPairs = pairs.Where(pair => pair.Count() == iHighest);
Here is the comparer.
public class PairComparer : IEqualityComparer<IList<int>>
{
public bool Equals(IList<int> x, IList<int> y)
{
return x.All(i => y.Contains(i));
}
public int GetHashCode(IList<int> obj)
{
return obj.Sum(x => x.GetHashCode());
}
}

Categories