getting main diagonal of square matrix in linear representation - c#

I have int array representing elements of square matrix. I need to get rows,columns, 2 main diagonals of it. I have trouble with getting second diagonal (for 3*3 matrix it is elements with indexes 2,4,6 for 6*6 - 5,10,15,20,25,30). I'm wondering is there a neat way to do it without for loops.
var matrix = new int[] { 6, 7, 2, 1, 5, 9, 8, 3, 4 };
int size = 3;
int i = 0;
var rows = matrix.GroupBy(x => i++ / size);
i = 0;
var columns = matrix.GroupBy(x => i++ % size);
var diag1 = matrix.Where((x, index)=>index%(size+1)==0);
var diag2 = matrix.Where((x, index) => index % (size - 1) == 0);//PROBLEM - takes 0,8 indexes also.

Try this
var matrix = new int[] { 6, 7, 2, 1, 5, 9, 8, 3, 4 };
int size = 3;
var rows = matrix.Select((x,i) => new {x = x, i = i}).GroupBy(x => x.i / size).Select(x => x.Select(y => y.x).ToArray()).ToArray();
var columns = matrix.Select((x, i) => new { x = x, i = i }).GroupBy(x => x.i % size).Select(x => x.Select(y => y.x).ToArray()).ToArray();
var diag1 = matrix.Where((x, index) => (index /size) == (index % size)).Select(x => x).ToArray();
var diag2 = matrix.Where((x, index) => (index / size) == (size - 1) - (index % size)).Select(x => x).ToArray();

Related

How to distribute an array to smaller arrays randomly?

I want to create same sized smaller arrays from a big array. But items should distribte randomly. I can distribute by order like following:
int[] source = new[] { 10, 20, 30, 40, 50, 60, 70, 80, 90 };
int i = 0;
int chunkSize = 3;
var result = source.GroupBy(s => i++ / chunkSize).Select(g => g.ToArray()).ToArray();
// [10,20,30][40,50,60][70,80,90]
But result should be random like: // [90,20,50][70,30,60][40,80,10]
Can I do it using linq?
The following implements the suggestions in the comments to add an OrderBy clause. There are, of course, other ways to achieve the result, but this is likely the simplest way using LINQ, as requested.
int[] source = new[] { 10, 20, 30, 40, 50, 60, 70, 80, 90 };
int i = 0;
int chunkSize = 3;
Random r = new Random();
var result = source.OrderBy(x => r.Next()).GroupBy(s => i++ / chunkSize).Select(g => g.ToArray()).ToArray();
You can shuffle any 1D array with this method.
If you modify it to return IList<T> instead of void, you can append it into your query:
var result = source.Shuffle().GroupBy(...)
You could do the following.
var arr = new int[] { 1, 1, 2, 6, 6, 7, 1, 1, 0 };
var sizeOfResultArray = 3;
var result = arr.ChunkBy(sizeOfResultArray);
The extension methods are defined as
public static class Extensions
{
private static Random rng = new Random();
public static IEnumerable<IEnumerable<T>> ChunkBy<T>(this IEnumerable<T> source, int chunkSize)
{
return source.Shuffle()
.Select((x, i) => new { Index = i, Value = x })
.GroupBy(x => x.Index / chunkSize)
.Select(x => x.Select(v => v.Value).ToList())
.ToList();
}
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> list)
{
var collection = list.ToList();
int n = collection.Count();
while (n > 1)
{
n--;
int k = rng.Next(n + 1);
T value = collection[k];
collection[k] = collection[n];
collection[n] = value;
}
return collection;
}
}
The Shuffle is a Fisher-Yates shuffle implementation by Grenade here
You need to randomize and then group. Code below should work
int[] source = new[] { 10, 20, 30, 40, 50, 60, 70, 80, 90 };
Random rand = new Random();
int[] random = source.Select(x => new { num = x, rand = rand.Next() }).OrderBy(x => x.rand).Select(x => x.num).ToArray();
int groupsize = 3;
int[][] groups = random.Select((x, i) => new { num = x, index = i })
.GroupBy(x => x.index / groupsize)
.Select(x => x.Select(y => y.num).ToArray())
.ToArray();

C# - How to find the most common and the least common integers in an array?

I was asked to make a Dice program with two arrays (one for each dice) and add the two results, e.g.: 2 (dice 1) + 6 (dice 2) = 8.
The program must roll the dices 100 times and show the sum each time.
I could do it so far, but the program also must show which sum is the most frequent, and which sum is the least frequent.
Like this: sum = [2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6]. Most common: 2; Least common: 5.
How can I do it?
This is how my code looks like:
static void Main(string[] args)
{
Random gerador = new Random();
int[] soma = new int[100];
int rolagem = 0;
for(int i = 0; i < soma.Length; i++)
{
rolagem = 0;
rolagem += gerador.Next(6) + 1;
rolagem += gerador.Next(6) + 1;
soma[i] = rolagem;
}
var mais = soma.GroupBy(item => item).OrderByDescending(g => g.Count()).Select(g => g.Key).First();
//NEED TO FIND OUT LEAST COMMON SUM
for (int j = 1; j < soma.Length; j++)
{
Console.Write("{0} ", soma[j]);
}
Console.WriteLine("Soma mais frequente: {0}, Soma menos frequente: {1}", mais, menos);
Console.ReadKey();
}
You're almost there, you can find the least common one similarly:
var array = new[] { 1, 1, 1, 1, 4, 2, 2, 3, 3, 3, 5, 5 };
var result = array.GroupBy(i => i).OrderBy(g => g.Count()).Select(g => g.Key).ToList();
var mostCommon = result.Last();
var leastCommon = result.First();
If you have code that rolls the dice 100 times, you are pretty close. All you need to do is frequency counters.
A roll of a pair of dice yields a number between 2 and 12, inclusive. Make an int count[13] array before entering the loop.
In the loop each time you have two numbers, say, d1 and d2, increment the count as follows:
count[d1+d2]++;
Once the loop is over, find the highest and the lowest numbers in the array between indexes 2 and 12, inclusive. The index of the highest number will be the number with the highest roll count; the index of the lowest number will be the number with the lowest roll count.
Tuple<int, int> least = new Tuple<int, int>(-1, -1), most = new Tuple<int, int>(-1, -1);
List<int> arr = new List<int> { 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6 };
var grp = arr.GroupBy(x => x).Select(x=>x).ToList();
foreach (var item in grp)
{
if (least.Item2 == -1 || least.Item2>item.Count())
{
var x = new Tuple<int, int>(item.Key, item.Count());
least = x;
}
if (most.Item2 == -1 || most.Item2 < item.Count())
{
var x = new Tuple<int, int>(item.Key, item.Count());
most = x;
}
}
Console.WriteLine("Least : "+least.Item1+" repeated " + least.Item2+"times");
Console.WriteLine("Most : "+most.Item1 + " repeated " + most.Item2 + "times");
Or as m1kael suggested,
Tuple<int, int> least = new Tuple<int, int>(-1, -1), most = new Tuple<int, int>(-1, -1);
List<int> arr = new List<int> { 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6 };
var grp = arr.GroupBy(x => x).OrderBy(x=>x.Count()).Select(x => x.Key).ToList();
Console.WriteLine("Least : "+ grp.First());
Console.WriteLine("Most : "+ grp.Last());
There is a small chance for more than one most or least common:
var a = Enumerable.Repeat(new Random(), 100).Select(r => r.Next(6) + r.Next(6) + 2);
var groups = a.GroupBy(i => i).GroupBy(g => g.Count(), g => g.Key).OrderBy(g => g.Key).ToList();
var mostCommon = string.Join(", ", groups.Last());
var leastCommon = string.Join(", ", groups[0]);

Feedback Loop Filtering query using LINQ [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have the following scenario (based on an actual scenario that cannot be shown here). Two inputs
A number x
A series of positive integers given as IEnumerable<int>
Now I want to find all groups of three consecutive integers in the series that can divide x with no remainder, and one group cannot overlap the other.
For instance: My series is 1, 2, 3, 4, 5, 6 and user inputs x=24
Then my LINQ will give 1, 2, 3, but will not give 2, 3, 4 because those two groups will overlap in the series.
Now I could run a LINQ query that would basically run a "window" of 3 on the series and give me the several groups, and run a Where clause to find the group that will have all 3 numbers successfully dividing x. But every time I find a match, I need some kind of a negative feedback to tell my filter to omit the subsequent groups that will be overlapping to the matching one.
To understand it better, in the above example. I can generate several groups like
1, 2, 3
2, 3, 4
3, 4, 5,
and so on
then I could say
myWindowsOf3Numbers
.Where(w => x % w.Number1 == 0 && x % w.Number2 == 0 && x % w.Number3 == 0)
So I end up with code like this
var series = new[] { 1, 2, 3, 4, 5, 6, 7 };
var x = 24;
var windows = series.Select((number, index) => index + 2 < series.Count()? new { Number1 = series[index], Number2 = series[index+1], Number3 = series[index+2] } : null )
.Where(groups => groups != null);
var matching = windows.Where(w => x % w.Number1 == 0 && x % w.Number2 == 0 && x % w.Number3 == 0);
The above will give me 1, 2, 3 and 2, 3, 4 both, but I want only the first one of the two overlapping.
Is there any LINQ-trick to do that or I have to use foreach (Like the following code)?
private class Match
{
public int N1 { get; set; }
public int N2 { get; set; }
public int N3 { get; set; }
}
var series = new[] { 1, 2, 3, 4, 5, 6, 7 };
var x = 24;
var windows = series.Select((number, index) => index + 2 < series.Count() ? new { Number1 = series[index], Number2 = series[index + 1], Number3 = series[index + 2] } : null)
.Where(groups => groups != null);
var matches = new List<Match>();
for (var i = 0; i < (series.Count() - 2); i ++)
{
if (x % series[i] == 0 && x % series[i + 1] == 0 && x % series[i + 2] == 0)
{
matches.Add(new Match() { N1 = series[i], N2 = series[i + 1], N3 = series[i + 2] });
i += 3;
}
}
For the sake of the challenge, here is one possible "pure" LINQ solution, but frankly I'd never use something like this:
int x = 60;
var series = new [] { 1, 2, 3, 4, 5, 6 }.AsEnumerable();
var matches = series
// Create the sliding window
.Select((e, i) => new { index = i, group = series.Skip(i).Take(3).ToArray() })
// Remove the non matching
.Where(e => e.group.Length == 3 && e.group.All(v => (x % v) == 0))
// Remove the overlapping
.Aggregate(new { next = 0, result = Enumerable.Empty<int[]>() }, (prev, next) =>
next.index >= prev.next ?
new { next = next.index + 3, result = prev.result.Concat(new[] { next.group }) } :
prev).result;
Well, you said LINQ ...:
var series = new[] { 1, 2, 3, 4, 5, 6, 7 };
var x = 24;
var matchingWindows = series
.Select((number, index) => index + 2 < series.Length ?
new { Number1 = series[index], Number2 = series[index + 1], Number3 = series[index + 2], Index = index } :
null)
.Where(groups => groups != null)
.Where(w => x % w.Number1 == 0 && x % w.Number2 == 0 && x % w.Number3 == 0)
.ToList();
int lastTakenIndex = -1;
var nonOverlapping = matchingWindows.Where(w =>
{
if (lastTakenIndex >= 0)
{
if (w.Index <= lastTakenIndex + 2) return false;
lastTakenIndex = w.Index;
return true;
}
lastTakenIndex = w.Index;
return true;
}).ToList();
It uses a lastTakenIndex (= the start index of the 3-group that was last taken that matched the condition) which is modified as a side-effect during the Where filtering.

How can I get the sum (average) value of three lists in C#?

I have three lists which each list represents only 0s and 1s which related to the pixel values of three images.
My question is how can I get the sum (average) of those three lists and represent it in a new list?
here is example of my image1:
List<int> image1 = new List<int>();
int blackColor = 0;
for (int x = 0; x < bmp1.Width; x++)
{
for (int y = 0; y < bmp1.Height; y++)
{
Color color = bmp1.GetPixel(x, y);
if (color.ToArgb() == Color.Black.ToArgb())
{
image1.Add(0);
blackColor++;
}
else
{
image1.Add(1);
}
}
}
Let me makes sure I understand the problem. You have three lists of the same length:
list A: 1, 2, 4, 3
list B: 3, 2, 4, 1
List C: 2, 7, 1, 8
and you wish to get a third list that is the average of each:
List D: 2, 4, 3, 4
Yes?
This is a job for zip join.
var sumOfFirstTwo = list1.Zip(list2, (x, y)=>x + y);
sumOfFirstTwo is now the sequence that is the sum of the first two lists.
var sumOfAllThree = sumOfFirstTwo.Zip(list3, (x, y)=>x + y);
sumOfAllThree is now the sequence that is the sum of all three lists.
var average = sumOfAllThree.Select(x=>x/3).ToList();
Make sense?
This works for an arbitrary number of lists
var firstList = new[] { 1, 2, 3, 1 };
var secondList = new[] { 2, 3, 1, 1 };
var thirdList = new[] { 3, 1, 2, 2 };
var lists = new[] { firstList, secondList, thirdList };
var listLengths = lists.Select(x => x.Count());
if (listLengths.Distinct().Count() != 1)
throw new Exception("Line lengths must be the same");
var lengthOfEachList = listLengths.First();
var averages = new List<double>();
for (var i = 0; i != lengthOfEachList; ++i) {
averages.Add(lists.Average(x => x[i]));
}
The LINQ way would be
var averages = Enumerable.Range(0, lengthOfEachList).Select(x => lists.Average(y => y[x]));

Sort an integer array by given starting integer

I have an array:
int[] months = new int[4] {1, 4, 7, 10};
I would like to sort the array starting by the given value and sort the rest of the array in the original order.
Let's say I want to start sorting the array by a value of 7. The sorted array would be then in order of:
7, 10, 1, 4
Or starting with a value 4 the sorted array would be an order of
4, 7, 10, 1
How about:
var orderedMonths = months.Where(x => x >= 7)
.OrderBy(x => x)
.Concat(months.Where(x => x < 7));
Note that this will mean that the elements of the "rest of the array" will be in order of appearance rather than increasing numeric order. If you meant the latter (i.e. sort both 'segments' numerically) , I would do:
var orderedMonths = months.OrderBy(x => x < 7) // false comes before true
.ThenBy(x => x);
On the other hand, if you want to sort both segments by order of appearance, I would do:
var orderedMonths = months.GroupBy(x => x < 7)
.OrderBy(group => group)
.SelectMany(x => x);
(or)
var orderedMonths = months.Where(x => x >= 7)
.Concat(months.Where(x => x < 7));
Assuming this is your sorted int array you could
int[] months = new int[4] { 1, 4, 7, 10 };
int value = 10;
int[] chk1 = new int[4];
chk1 = months.SkipWhile(a => a != value).
Concat(months.TakeWhile(a => a != value)).ToArray();
This should get you the required order
Can you use a list?
int NumberToBeFound = 7;
int IndexOfNumber = -1;
for(int i=0;i<months.count;i++){
if(months[i] == NumberToBeFound){
IndexOfNumber = i;
break;
}
}
List<int> Sorted = new List<int>();
for(int i = IndexOfNumber; i < months.count;i++){
Sorted.Add(months[i]);
}
for(int i = 0; i < IndexOfNumber; i++){
Sorted.Add(months[i]);
}
months = Sorted.ToArray();

Categories

Resources