Finding Max Question - c#

I have such a list List<Double[,]>. Let's call each 2-dimensional array in the list a layer. So I should compare each element in each layer and extract max. And construct layer of max values.
How do I do that? Maybe with use of LINQ? Or foreach loop construction?
Help!
And Thanks!

var x = new double[,] { { 1, 2 }, { 3, 4 } };
var y = new double[,] { { 5, 6 }, { 7, 8 } };
var list = new List<double[,]> { x, y };
var maxValues = list
.Select(arg => arg.Cast<double>().Max())
.ToList();
So as I understand x and y are levels.
The the result will be 4 and 8, which are max on level x and y respectively.
[Edit]
Seems like I misunderstood the question.
To find the level with max you can use code like this:
var maxLevel = list
.Select(arg => new { Max = arg.Cast<double>().Max(), Level = arg })
.OrderByDescending(arg => arg.Max)
.Select(arg => arg.Level)
.First();

Assuming that all your layers are the same size sizeXxsizeY, because otherwise this makes no sense:
var maxLayer = new Double[sizeX,sizeY];
for( int x = 0; x <= maxLayer.GetUpperBound(0); x++ )
for( int y = 0; y <= maxLayer.GetUpperBound(1); y++ )
maxLayer[x,y] = Double.NegativeInfinity;
foreach( Double[,] layer in list )
for( int x = 0; x <= maxLayer.GetUpperBound(0); x++ )
for( int y = 0; y <= maxLayer.GetUpperBound(1); y++ )
maxLayer[x,y] = Math.Max( maxLayer[x,y], layer[x,y] );
Nothing clever here.

Related

Group list into groups by the the index range of the list

I have a source integer list with numbers from 0 to 50.
Then I want to have a grouped target list that means:
group1: 1,2,3,4,5,6,7,8,9,10
group2: 11,12,13,14,15,16,17,18,19,20
group3: etc... ,30
group4: etc... ,40
group5: etc... ,50
The groupFactor here is 5.
How can I group my integer list basing on that group factor which could be any number?
UPDATE
If the group factor is 6
there would be an additional:
group6: etc... ,60
Let k be your group factor. Group your list by multiplying the list member by k then dividing by 50, and grouping the sequence on the resulting quotient.
Your question is a little vague but for the sample you provided, I found this fancy group by :)
var list = new List<int>();
for (int i=0; i <= 50; i++)
{
list.Add(i);
}
var result = list.GroupBy( n => (n-1)/10 );
Try this
static void Main(string[] args)
{
List<int> input = new List<int>();
for (int i = 0; i <= 50; i++)
{
input.Add(i);
}
List<List<int>> output = input.Select((x, i) => new { x = x, i = (int)(x / 10) }).GroupBy(y => y.i).Select(z => z.Select(a => a.x).ToList()).ToList();
}

Linq one Result from multiple Lists

I have one method that calculates a score. simplified:
public static int GetScore(int v1, int v2, char v3)
{
//calculate score
return score;
}
v1, v2 and v3 are 3 values from 3 lists:
List<int> Values1 = new List<int>();
List<int> Values2 = new List<int>();
List<char> Values3 = new List<char>();
//fill Values1, Values 2, Values3
How must be the Select to determine each combination of the three lists and determine the highest score? I thought of something like that:
int MaxScore = Values1.Select(x => Values2.Select(y => GetScore(x, y))).Max(); // ???
My current approach
int MaxScore = 0;
foreach (int x in Values1)
{
foreach (int y in Values2)
{
foreach (char z in Values3)
{
int Score = GetScore(x, y, z);
if (Score > MaxScore)
{
MaxScore = Score;
}
}
}
}
In this case I think LINQ Query syntax is more clear.
var data = from v1 in Values1
from v2 in Values2
from v3 in Values3
select GetScore(v1, v2, v3);
var max = data.Max();
As per the suggestion in my comment, you can do this:
int MaxScore =
Values1
.SelectMany(x =>
Values2
.SelectMany(y =>
Values3
.Select(z =>
GetScore(x, y, z))))
.Max();

C# algorithm refactor splitting an array into 3 parts?

I have an IEnumerable and I wanted to split the data across 3 columns using the following business logic. if 3 or less items, 1 item per column, anything else I wanted to divide the total items by 3 split the leftovers (either 1 or 2 items) between the first two columns. Now this is pretty ugly but it does the job. I'm looking for tips to leverage linq a little better or possibly eliminate the switch statement. Any advice or tips that improve the code are appreciated.
var numItems = items.Count;
IEnumerable<JToken> col1Items,
col2Items,
col3Items;
if(numItems <=3)
{
col1Items = items.Take(1);
col2Items = items.Skip(1).Take(1);
col3Items = items.Skip(2).Take(1);
} else {
int remainder = numItems % 3,
take = numItems / 3,
col1Take,
col2Take,
col3Take;
switch(remainder)
{
case 1:
col1Take = take + 1;
col2Take = take;
col3Take = take;
break;
case 2:
col1Take = take + 1;
col2Take = take + 1;
col3Take = take;
break;
default:
col1Take = take;
col2Take = take;
col3Take = take;
break;
}
col1Items = items.Take(col1Take);
col2Items = items.Skip(col1Take).Take(col2Take);
col3Items = items.Skip(col1Take + col2Take).Take(col3Take);
Ultimately I am using these in a mvc Razor view
<div class="widgetColumn">
#Html.DisplayFor(m => col1Items, "MenuColumn")
</div>
<div class="widgetColumn">
#Html.DisplayFor(m => col2Items, "MenuColumn")
</div>
<div class="widgetColumn">
#Html.DisplayFor(m => col3Items, "MenuColumn")
</div>
In my first attempt I want to get rid of the colNItems and colNTake variables but i can't figure out the correct algorithm to make it work the same.
for (int i = 1; i <= 3; i++ )
{
IEnumerable<JToken> widgets = new List<JToken>();
var col = i;
switch(col)
{
case 1:
break;
case 2:
break;
case 3:
break;
}
}
Are the columns fixed-width? If so, then there's no need to do anything special with your collection. Just rely on the browser to do it for you. Have an outer container that has the overall width of the 3 columns, then just fill it with a div for each item (and float left). Set your inner containers to have a width exactly 1/3 of the outer container.
Here's a quick fiddle
Here's a quick hint at the style
div#outer{
width:300px;
}
div#outer > div{
width:100px;
float:left;
}
You could generalize:
int cols = 3;
IEnumerable<JToken> colItems[3]; // you can make this dynamic of course
int rem = numItems % cols;
int len = numItems / cols;
for (int col=0; col<cols; col++){
int colTake = len;
if (col < rem) colTake++;
colItems[col] = items.Skip(col*len).Take(colTake);
}
Haven't tested, but this should work for any number of columns.
Also whenever you need variables col1, col2, col3 think of col[0], col[1], col[2].
Can't you just do something like?
int len = numItems / 3;
int rem = numItems % 3;
int col1Take = len + (rem > 0 ? 1 : 0);
int col2Take = len + (rem > 1 ? 1 : 0);
int col3Take = len;
Edit:
A more generic solution that works for any number of columns (COLUMNS) would be:
int len = numItems / COLUMNS;
int rem = numItems % COLUMNS;
foreach (var i in Enumerable.Range(0, COLUMNS)) {
colTake[i] = len + (rem > i ? 1 : 0);
}
So you want the first n/3 items in the first column, next n/3 items in the 2nd column, etc.
var concreteList = items.ToList();
var count = concreteList.Count;
var take1 = count/3 + (count % 3 > 0 ? 1 : 0);
var take2 = count/3 + (count % 3 > 1 ? 1 : 0);
var col1 = concreteList.Take(take1);
var col2 = concreteList.Skip(take1).Take(take2);
var col3 = concreteList.Skip(take1 + take2);
I make a concrete list in order to avoid iterating the Enumerable multiple times. For example, if you had:
items = File.ReadLines("foo.txt");
Then you wouldn't be able to iterate it multiple times.
If you want to fill the columns round-robin you can use:
int numColumns = 3;
var result = Enumerable.Range(1,numColumns).Select(c =>
items.Where((x,ix) => ix % numColumns == c-1).ToArray()
);
This isn't fast, but it'll do the trick:
var col1Items = items.Select((obj, index) => new { Value = obj, Index = index })
.Where(o => o.Index % 3 == 0).Select(o => o.Value);
var col2Items = items.Select((obj, index) => new { Value = obj, Index = index })
.Where(o => o.Index % 3 == 1).Select(o => o.Value);
var col3Items = items.Select((obj, index) => new { Value = obj, Index = index })
.Where(o => o.Index % 3 == 2).Select(o => o.Value);
It uses the version of Select that includes an index parameter. You could use a GroupBy to speed this up a bit at the cost of a few lines of code.
If you want to go across then down see answer below this one, if you want to go down then across you can do it like this (use this code with the test below to see it working instead of the var result line there.:
var curCol = 0;
var iPer = items.Count() / 3;
var iLeft = items.Count() % 3;
var result = items.Aggregate(
// object that will hold items
new {
cols = new List<ItemElement>[3] { new List<ItemElement>(),
new List<ItemElement>(),
new List<ItemElement>(), },
},
(o, n) => {
o.cols[curCol].Add(n);
if (o.cols[curCol].Count() > iPer + (iLeft > (curCol+1) ? 1:0))
curCol++;
return new {
cols = o.cols
};
});
You can do this with aggregate. It would look like this:
void Main()
{
List<ItemElement> items = new List<ItemElement>() {
new ItemElement() { aField = 1 },
new ItemElement() { aField = 2 },
new ItemElement() { aField = 3 },
new ItemElement() { aField = 4 },
new ItemElement() { aField = 5 },
new ItemElement() { aField = 6 },
new ItemElement() { aField = 7 },
new ItemElement() { aField = 8 },
new ItemElement() { aField = 9 }
};
var result =
items.Aggregate(
// object that will hold items
new {
cols = new List<ItemElement>[3] { new List<ItemElement>(),
new List<ItemElement>(),
new List<ItemElement>(), },
next = 0 },
// aggregate
(o, n) => {
o.cols[o.next].Add(n);
return new {
cols = o.cols,
next = (o.next + 1) % 3
};
});
result.Dump();
}
public class ItemElement
{
public int aField { get; set; }
}
You end up with an object with an array of 3 lists (one for each column).
This example will run as is in linqPad. I recomment linqPad for these kind of POC tests. (linqPad.com)
it might help
IEnumerable<object> items = new Object[]{ "1", "2", "3", "4", "5", "6", "7","8", "9", "10", "11", "12","13", "14" };
IEnumerable<object> col1Items = new List<object>(),
col2Items = new List<object>(),
col3Items = new List<object>();
Object[] list = new Object[]{col1Items, col2Items, col3Items};
int limit = items.Count()/3;
int len = items.Count();
int col;
for (int i = 0; i < items.Count(); i++ )
{
if (len == 3) col = i;
else col = i / limit;
if (col >= 3) col = i%limit ;
((IList<object>)(list[col])).Add( items.ElementAt(i));
}
LinqLib (nuget: LinqExtLibrary) has an overload of ToArray() that does it:
using System.Collections.Generic;
using System.Linq;
using LinqLib.Array;
...
public void TakeEm(IEnumerable<int> data)
{
var dataAry = data as int[] ?? data.ToArray();
var rows = (dataAry.Length/3) + 1;
//var columns = Enumerable.Empty<int>().ToArray(3, rows);
// vvv These two lines are the ones that re-arrange your array
var columns = dataAry.ToArray(3, rows);
var menus = columns.Slice();
}

Grouping list elements to dictionary

I have a list that contains 8 elements:
ConfigFile.ControllerList
this list is type of:
List<Controller>
How can i add Controllers from ControllerList to 3 dictionary keys. Dictionary is like:
Dictionary<int, List<Controller>> ControllerDictionary = new Dictionary<int, List<Controller>>();
I want to add first 3 controllers to dictionary key 0, then want to add next 3 controllers to dictionary key 1 and lastly want to add last 2 controllers to dictionary key 2. How can i do that?
You can use / to split the list into sub-list:
var ControllerDictionary = ControllerList
.Select((c, i) => new { Controller = c, Index = i })
.GroupBy(x => x.Index / maxGroupSize)
.Select((g, i) => new { GroupIndex = i, Group = g })
.ToDictionary(x => x.GroupIndex, x => x.Group.Select(xx => xx.Controller).ToList());
The idea is to first group the elements by indexes, then divide them by an int maxGroupSize(in your case 3). Then convert each group to a list.
Not sure if there's a more elegant solution, but something like this should work:
var dict = new Dictionary<int, List<Controller>>();
int x = 0;
while (x < controllerList.Count)
{
var newList = new List<Controller> { controllerList[x++] };
for (int y = 0; y < 2; y++) // execute twice
if (x < controllerList.Count)
newList.Add(controllerList[x++]);
dict.Add(dict.Count, newList);
}
To make it more general, you could also create newList empty to start, and then change y < 2 to y < GROUP_SIZE where GROUP_SIZE is whatever sized groups you want. Could even then extract this to an extension method:
public static Dictionary<int, List<T>> ToGroupedDictionary<T>
(this IList<T> pList, int pGroupSize)
{
var dict = new Dictionary<int, List<T>>();
int x = 0;
while (x < pList.Count)
{
var newList = new List<T>();
for (int y = 0; y < pGroupSize && x < pList.Count; y++, x++)
newList.Add(pList[x]);
dict.Add(dict.Count, newList);
}
return dict;
}
And then you can do this:
var groups = new[]
{
"Item1",
"Item2",
"Item3",
"Item4",
"Item5",
"Item6",
"Item7",
"Item8"
}.ToGroupedDictionary(3);

LINQ: Evaluating a function where array elements are matched by index

Say I have a function c[i] = f(x[i], y[i]). I have the input value arrays x and y of equal length and I want to calculate the values of array c in the end. How do I get that using LINQ?
i.e. without having to write:
c = new double[x.Length];
for (int i = 0; i < x.Length; i++)
{
c[i] = f(x[i], y[i]);
}
Use Zip method, e.g.:
int[] x = { 1, 2, 3 };
int[] y = { 4, 5, 6 };
var result = x.Zip(y, (i, j) => i + j);
or if you have already method with adequate params, simply use:
var result = x.Zip(y, Function);
// in this sample Function looks like:
static int Function(int x, int y)
{
return x + y;
}
You can use a simple Select:
var c = x.Select((x_i, i) => f(x_i, y[i]));
If c needs to be an int[] instead of IEnumerable<int>, append ToArray to the end:
var c = x.Select((x_i, i) => f(x_i, y[i])).ToArray();
You can use the Zip method to calculate
int[] a = { 4, 2, 3 };
int[] b = { 9, 1, 0 };
var result = a.Zip(b, (i, j) => i + j);

Categories

Resources