Grouping list elements to dictionary - c#

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);

Related

Sorting array by frequency of elements in C#

Here is what i have so far
int[] numbers = { 3,5,4,3,8,8,5,3,2,1,9,5 };
int[] n = new int[12];
int[] k;
foreach (int number in numbers)
{
n[number]++;
}
Array.Sort(n);
Array.Reverse(n);
foreach (int value in n)
{
Console.WriteLine(value);
}
I know i am missing the part where i sort the frequency of the elements after i counted them and i just cant get my head around it. I'd appreciate some help, Thanks!
What's the problem with your solution ?
Whereas you correctly keep the frequencies of the numbers in the table called n in your code, which hereby I would call it frequencies, then you Sort this array. This action breaks your solution, since each frequency is associated with the corresponding index of its location in the array.
E.g. If an instance of this array is this [8,2,1,7,6]. When you call the Sort method on this array, this would have as a result the array to be sorted and the order of the elements of the array would be this [1,2,7,6,8]. Before calling sort, the first element of the array was indicating that the number 0 (the index of the first element is 0) has been found 8 times in our numbers. After sort, the first element is 1, which means now that the frequency of the number 0 is 1, which is apparently wrong.
If you want to keep it your way, then you could try something like this:
int[] numbers = { 1,2,2,9,1,2,5,5,5,5,2 };
int[] frequencies = new int[12];
int k = 3;
foreach (int number in numbers)
{
frequencies[number]++;
}
var mostFrequentNumbers = frequencies.Select((frequency, index) => new
{
Number = index,
Frequency = frequency
})
.OrderByDescending(item => item.Frequency)
.Select(item => item.Number)
.Take(k);
foreach (int mostFrequentNumber in mostFrequentNumbers)
{
Console.WriteLine(mostFrequentNumber);
}
Are there any other approaches ?
An easy way to do this is to use a data structure like a Dictionary, in which you would keep as keys the numbers and as the corresponding values the corresponding frequencies.
Then you can order by descending values the above data structure an keep the k most frequent numbers.
int[] numbers = { 1,2,2,9,1,2,5,5,5,5,2 };
int k = 3;
Dictionary<int, int> numberFrequencies = new Dictionary<int, int>();
foreach (int number in numbers)
{
if(numberFrequencies.ContainsKey(number))
{
numberFrequencies[number] += 1;
}
else
{
numberFrequencies.Add(number, 1);
}
}
var mostFrequentNumbers = numberFrequencies.OrderByDescending(numberFrequency => numberFrequency.Value)
.Take(k)
.Select(numberFrequency => numberFrequency.Key);
foreach (int mostFrequentNumber in mostFrequentNumbers)
{
Console.WriteLine(mostFrequentNumber);
}
You can also achieve the same thing by only using LINQ:
int[] numbers = { 1,2,2,9,1,2,5,5,5,5,2 };
int k = 3;
var mostFrequentNumbers = numbers.GroupBy(number => number)
.ToDictionary(gr => gr.Key, gr => gr.Count())
.OrderByDescending(keyValue => keyValue.Value)
.Take(k)
.Select(numberFrequency => numberFrequency.Key);
foreach (int mostFrequentNumber in mostFrequentNumbers)
{
Console.WriteLine(mostFrequentNumber);
}
You can just use Linq extensions:
using System.Linq;
using System.Collections.Generic;
...
private static IEnumerable<int> Solve(int[] numbers, int k) {
return numbers
.GroupBy(x => x)
.OrderByDescending(g => g.Count())
.Select(g => g.Key)
.Take(k);
}
Then you can call:
var numbers = new []{1,2,2,9,1,2,5,5,5,5,2};
var k = 3;
var result = Solve(numbers, k);
foreach (int n in result)
Console.WriteLine(n);
To be very terse:
var frequents = numbers.GroupBy(t => t)
.Where(grp => grp.Count() > 1)
.Select(t => t.Key)
.OrderByDescending(t => t)
.Take(k)
.ToList();

Mapping a list of ints into a list of MinMax ranges with LINQ [duplicate]

When i have a list
IList<int> list = new List<int>();
list.Add(100);
list.Add(200);
list.Add(300);
list.Add(400);
list.Add(500);
What is the way to extract a pairs
Example : List elements {100,200,300,400,500}
Expected Pair : { {100,200} ,{200,300} ,{300,400} ,{400,500} }
The most elegant way with LINQ: list.Zip(list.Skip(1), Tuple.Create)
A real-life example: This extension method takes a collection of points (Vector2) and produces a collection of lines (PathSegment) needed to 'join the dots'.
static IEnumerable<PathSegment> JoinTheDots(this IEnumerable<Vector2> dots)
{
var segments = dots.Zip(dots.Skip(1), (a,b) => new PathSegment(a, b));
return segments;
}
This will give you an array of anonymous "pair" objects with A and B properties corresponding to the pair elements.
var pairs = list.Where( (e,i) => i < list.Count - 1 )
.Select( (e,i) => new { A = e, B = list[i+1] } );
You can use a for loop:
var pairs = new List<int[]>();
for(int i = 0; i < list.Length - 1; i++)
pairs.Add(new [] {list[i], list[i + 1]);
You can also use LINQ, but it's uglier:
var pairs = list.Take(list.Count - 1).Select((n, i) => new [] { n, list[i + 1] });
EDIT: You can even do it on a raw IEnumerable, but it's much uglier:
var count = list.Count();
var pairs = list
.SelectMany((n, i) => new [] { new { Index = i - 1, Value = n }, new { Index = i, Value = n } })
.Where(ivp => ivp.Index >= 0 && ivp.Index < count - 1) //We only want one copy of the first and last value
.GroupBy(ivp => ivp.Index, (i, ivps) => ivps.Select(ivp => ivp.Value));
More general would be:
public static IEnumerable<TResult> Pairwise<TSource, TResult>(this IEnumerable<TSource> values, int count, Func<TSource[], TResult> pairCreator)
{
if (count < 1) throw new ArgumentOutOfRangeException("count");
if (values == null) throw new ArgumentNullException("values");
if (pairCreator == null) throw new ArgumentNullException("pairCreator");
int c = 0;
var data = new TSource[count];
foreach (var item in values)
{
if (c < count)
data[c++] = item;
if (c == count)
{
yield return pairCreator(data);
c = 0;
}
}
}
Following solution uses zip method. Zip originalList and originalList.Skip(1) so that one gets desired result.
var adjacents =
originalList.Zip(originalList.Skip(1),
(a,b) => new {N1 = a, N2 = b});
Using .Windowed() from MoreLINQ:
var source = new[] {100,200,300,400,500};
var result = source.Windowed(2).Select(x => Tuple.Create(x.First(),x.Last()));
Off the top of my head and completely untested:
public static T Pairwise<T>(this IEnumerable<T> list)
{
T last;
bool firstTime = true;
foreach(var item in list)
{
if(!firstTime)
return(Tuple.New(last, item));
else
firstTime = false;
last = item;
}
}

Find closest value in a list in C# with linq?

I've a list like this:
public List<Dictionary<int, int>> blanks { get; set; }
This keep some index values:
In addition I have also a variable named X. X can take any value. I want to find closest 'Key' value to X. For example:
If X is 1300, I want to take blanks index: 2 and Key: 1200.
How can I do this via linq? Or, is there any other solution?
Thanks in advance.
EDIT: What if it is not a Dictionary. What if it is a List like this:
List<List<int[]>> lastList = new List<List<int[]>>();
This time, I want to take first List's indexes and second List's index. For example, if X is 800, I want to take 0 and 0 (for index 0) and also take 1 and 1 (for index 1) How can I do this time?
var diffs = blanks.SelectMany((item, index) => item.Select(entry => new
{
ListIndex = index, // Index of the parent dictionary in the list
Key = entry.Key, // Key
Diff = Math.Abs(entry.Key - X) // Diff between key and X
}));
var closestDiff = diffs.Aggregate((agg, item) => (item.Diff < agg.Diff) ? item : agg);
Dictionary<int, int> closestKeyDict = blanks[closestKey.ListIndex];
int closestKey = closestDiff.Key;
int closestKeyValue = closestKeyDict[closestKey];
The SelectMany clause flattens all the dictionaries entries into a collection of { ListIndex, DictionaryKey, Difference } instances.
This flattened collection is then aggregated to retrieve the item with the minimum difference.
To answer your second questsion:
var diffs = blanks.SelectMany((list, listIndex) => list.
SelectMany((array, arrayIndex) => array.
Select((item, itemIndex) => new
{
ListIndex = listIndex,
ArrayIndex = arrayIndex,
ItemIndex = itemIndex,
Diff = Math.Abs(item - X)
})));
var closestDiff = diffs.Aggregate((agg, item) => (item.Diff < agg.Diff) ? item : agg);
Now in closestDiff you'll find the indices of the closes item (List index, array index and array item index)
This might not be the most optimized way but it should just work,
List<Dictionary<int, int>> blanks = new List<Dictionary<int, int>>
{
new Dictionary<int, int>{{100,200}},
new Dictionary<int, int>{{500,200}},
new Dictionary<int, int>{{700,200}},
new Dictionary<int, int>{{1200,200}},
new Dictionary<int, int>{{300,200}},
new Dictionary<int, int>{{200,200}},
new Dictionary<int, int>{{800,200}},
};
int x = 1300;
IEnumerable<int> keys = blanks.SelectMany(ints => ints.Keys);
var diff = keys.Select(i => Math.Abs(i - x)).ToList();
var index = diff.IndexOf(diff.Min());
var value = blanks[index].Keys.First();

String Split: Key not found exception

I have a string message that is separated by ':Item:' I want to put the items next to ':Item:' in a dictionary using a unique key
string input = "aaaaa:Item:ID1222222:Item:ID3444444:Item:ID4555555";
var response = new Dictionary<string, string>();
string[] values = input.Split(':');
for (int i = 0; i < values.Length; i++)
{
if (!values[i].Contains("Item"))
{
// use the id as a unique key
response.Add(values[i].Substring(1, 3), values[i]);
}
Console.WriteLine(response["ID1"]);
Console.ReadLine();
}
But this is giving me a key not found exception since values[0] does not have the ID i used as a key.
How can I skip the first element in the collection? or is there another efficient way?
EDIT:
What I want to put in the dictionary is :
key = "AA", value = "aaaaa"
key = "ID1", value = "ID1222222"
key = "ID3" valeu ="ID3444444"
key = "ID4" value "ID4555555"
thanks
You can use LINQ to get your expected output:
var dictionary = input.Split(':')
.Where(x => !x.Contains("Item"))
.ToDictionary(x => x.Substring(0, 3), x => x);
Results in LINQPad:
Note: Substring might throw exception if you have a key that contains less than three characters,in order to fix that you can do the following:
var dictionary = input.Split(':')
.Where(x => !x.Contains("Item"))
.ToDictionary(x => x.Length >=3 ? x.Substring(0, 3) : x, x => x);
string input = "aaaaa:Item:ID1222222:Item:ID3444444:Item:ID4555555";
var response = new Dictionary<string, string>();
string[] values = input.Split(':');
for (int i = 1; i < values.Length; i++)
{
if (!values[i].Contains("Item"))
{
// use the id as a unique key
response.Add(values[i].Substring(0, 3), values[i]);
}
}
for (int i = 0; i < response.Count; i++)
{
if (response.ContainsKey("ID1"))
{
Console.WriteLine(response["ID1"]);
Console.ReadLine();
}
}

Finding Max Question

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.

Categories

Resources