Find the Biggest List in a Dictionary of Lists - c#

Lets say I have:
Dictionary<string, List<string>> ourGroups = new Dictionary(string, List<string>>();
Dictionary contents (Key is based on a specific letter position as shown):
Key | Value | Total
-O- | "DOC", "HOP", "POP" | Total = 3
--- | "SIP", "PLZ", "SUZ", "UPS" | Total = 4
So key 2 contains our biggest list of values.
How would I place the biggest key Values into a separate list? What I tried:
List<string> finalGroup = new List<string>();
finalGroup = ourGroups.Values.Max();
Obviously I'm not doing this correctly. A bit of explanation on how this works would be appreciated.

You can use LINQ to sort by Values and select the first one like below .
var result = ourGroups.OrderByDescending(s => s.Value.Count()).First().Value;

If you intend to get the Key, which has Items in its Value (list), you could use
var keyWithMaxValue = ourGroups.Aggregate((l, item) => l.Value.Count > item.Value.Count ? l : item).Key;
If you need the Value (list)
var maxValue = ourGroups.Aggregate((l, item) => l.Value.Count > item.Value.Count ? l : item).Value;

Related

How to find key in Dictionary<DateTime, DataTable> by using Linq

I have a dictionary DateTime, DataTable
Key Values
2019/07/01 Column A | B
1 | 1
2019/07/02 Column A | B
3 | 4
2019/07/03 Column A | B
5 | 4
I would like to use linq to find the key of the dictionary with maximum value of column A in the dict.
In above case, my expected result is "2019/07/03"
I am new in linq. Is it possible for above use? How to do?
While .OrderByDescending(x=> x.Key).FirstOrDefault()?.Key; will give you the correct answer, it will result in first sorting the values which is time and memory inefficient.
What you want to do is scan all your values once without memory consumption:
KeyValuePair<MyKey, MyValue> maxKey;
if (list.Count > 0)
{
maxKey = list.Aggregate(list.First(), (first,second)=>first.Value.A>second.Value.A?first:second);
}
Another one example.
Dictionary<DateTime, int> example = new Dictionary<DateTime, int>()
{
{new DateTime(2019,07,01), 1 },
{new DateTime(2019,07,02), 2 },
{new DateTime(2019,07,03), 3 }
};
var HighestKey = example.Keys.Max();
Please try below solution, I am sure it will work.
<DictionaryName>.OrderByDescending(x => x.Key).First();

Combine multiple values into one in c#

I have a dictionary having ids as key and value will be the ids to which it will be clubbed ( which is actually the ref data).
There is one more list which only contains the ids but for specific name.
First list have 100 different ids from 1 to 100.
I am checking whether the ids for specific name in list 2 is present in list 1.If they are present then saving those ids. But there is a special condition in it.
e.g. If ids present in list 2 have clubbed ids (which we are checking from the ref dictionary) then we have to save only the clubbed id
Let us suppose the ids in list 2 is 1,10,21. 1 and 10 are clubbed with 21.Therefore, I only have to save one id which is the clubbed one i.e. 21 but not to save 1 and 10. In this case we are saving only 1 instead of 3.
If these ids dont have any clubbed id then 3 ids will be saved (1,10,21).
Updated:
Dictionary have 1 to 100 ids and some of the ids have clubbed ids and some dont
Dictionary<int,string> dict = new Dictionary<int,string>();
//Key is id and the value is clubbedid
dict.Add(1,"21");
dict.Add(10,"21");
dict.Add(21,"None");
// etc
//In the list 2 we have ids for specific name
List<int> list2 = new List<int>();
list2.Add(1);
list2.Add(10);
list2.Add(21);
First i will check whether all the three ids in list 2 are in reference dictionary.And then will assign the value in other list of object in the field Id.
foreach(int value on list2)
{
if(dict.ContainsKey(value))
{
List<class> list3 = new List<class> list3();
list3.Id = value;
}
}
So I have added all the three ids 1,10,21 one by one in id field of list3. Now the list3 contains three ids. In the simple case it is correct where none of the id have clubbed id.
But as you can see in my reference dictionary, ids 1 and 10 have clubbed id as 21.Therefore, in the list3 I have to store only one value which is 21 (only clubbed id removing the other one 1 and 10)
Any help.
Your question is not particularly clear - as per the comments currently.
To have a stab at this - assuming list1 is an IEnumerable<int> and list2 is a Dictionary<int,int[]> then I think what you're trying to do is along the lines of the following
// numbers 1-100
var list1 = Enumerable.Range(1,100).ToList();
// 3 entries
var list2 = new Dictionary<int,int[]>(){
{1,new[]{21}},
{10,new[]{21}},
{21,new int[0]}
};
var result = list2.SelectMany(item => {
if(!list1.Contains(item.Key))
return Enumerable.Empty<int>();
if(item.Value != null && item.Value.Length>0)
return item.Value;
return new[]{item.Key};
}).Distinct();
Live example: http://rextester.com/RZMEHU88506
Having updated your question, this might work for you:
var list3 = list2.Select(x => {
int value = 0;
// if the dict contains the key and the value is an integer
if(dict.ContainsKey(x) && int.TryParse(dict[x], out value))
return value;
return x;
})
.Distinct()
.Select(x => new MyClass(){ Value = x })
.ToList();
Live example: http://rextester.com/KEEY8337

Sorting lists in c#

I have two lists in C#.
public List<MyClass> objectList = new List<MyClass>(); // it is filled with MyClass objects
public List<int> numberList = new List<int>(); // it is filled with numbers
The index of numbers in the numberList correspond to object index in the objectList: For example: objectList[0] = o1 and numberList[0] = 3 ;
objectList[1] = o2 and numberList[1] = 5 ...
objectList: |o1 | o2 | o3 | o4 | o5 | ...
numberList: 3 5 6 1 4 ...
I want to sort the numbers in the numberList in ascending order and I want for the objetcs in objectList to move with them:
After sorting:
objectList: |o4 | o1 | o5 | o2 | o3 | ...
numberList: 1 3 4 5 6 ...
In practical use I need this for implementing the Hill climbing algorithm on a N queen problem. In the objectList I store positions of all the queens on the board and in the numberList I store the calculated heuristics for the positions. Then I want to sort the numberList so I get the position with the lowest heuristic value. The goal is to move to the position with the lowest heuristic value.
Transform your object list into a sequence of items paired with their indices:
var pairs = objectList.Select(item, index) => new { item, index };
Now you have something you can use to do an ordering:
var orderedPairs = pairs.OrderBy(pair => numberList[pair.index]);
Now you have an ordered list of pairs. Turn that back into an ordered list of items:
var ordered = orderedPairs.Select(pair => pair.item);
and turn it into a list:
var orderedList = ordered.ToList();
Note that your original lists are not altered. This creates a new list that is in the order you want.
Of course you can do it all in one expression if you like:
objectList = objectList
.Select((item, index) => new { item, index } )
.OrderBy(pair => numberList[pair.index])
.Select(pair => pair.item)
.ToList();
Now, all that said: it sounds like you're doing too much work here because you've chosen the wrong data structure. It sounds to me like your problem needs a min heap implementation of a priority queue, not a pair of lists. Is there some reason why you're not using a priority queue?

The most efficient way to get object with max value from list of objects

I have an object called entry. It has min and max in float and fileName in string. And those objects are stored in a list
List<Entry> minMaxList = new List<Entry>();
I need to find an object(s) with the highest value and with the minimum value alongside with its file name.
So if I have an array like this
Entry1 Entry2 Entry3
min max filename min max filename min max filename
| 2 | 120 | file1.txt | | 2 | 150 | file1.txt | | 5 | 150 | file1.txt |
I want to get that the objects with the lowest value are Entry1 and Entry2 and objects with the highest value are Entry2 and Entry3
I tried this:
var max = minMaxList.Max(r => r.getMax())
which works good, but it returns me a single value, without any other information about where it came from. I need either the whole object, or at least the filenames in which this value is. I wonder if it can be done in a single command, or if I have to then iterate the list again and find all the entries base on the min and max selected earlier.
You can always filter the enumerable instead of only letting the maximum value through:
var maxvalue = minMaxList.Max(w => w.getMax());
var maxitems = minmaxlist.Where(w => w.getMax() == maxvalue);
You're close, you just need to add a filter that finds the matching items:
var max = minMaxList.Max(r => r.getMax())
var itemsWithMax = minMaxList.Where(r => r.getMax() == max);
and similarly with Min.
I wonder if it can be done in a single command
Probably, using complicated groupings or joins, but I would get something that works first and then try to make it better (remembering that a single query is not always "better" than multiple queries).
you're asking about the most efficient way to solve this.
determinig the max / min value and searching those items afterwards requires to iterate the list twice. I would solve it manually in one loop
List<Entry> ResultList = new List<Entry>();
ResultList.Add(minMaxList[0]);
foreach (Entry item in minMaxList)
{
if (item.getMax() >= ResultList[0].getMax())
{
if (item.getMax() != ResultList[0].getMax())
{
ResultList.Clear();
}
ResultList.Add(item);
}
}
Try with a group by:
var grpWithMaxVaues = minMaxList.GroupBy(c => c.getMax())
.OrderByDescending(c => c.Key)
.FirstOrDefault()
var max = grpWithMaxVaues.FirstOrDefault();
Console.WriteLine(max.FileName);
I find this to be the shortest way.
var newList = new List<Hero>();
var maxValue = newList.OrderByDescending(x => x.Level).ToList()[0];
I think The most efficient way is using Aggregate.
var itemWithMax = minMaxList
.Aggregate((current, next) =>
current.getMax() > next.getMax()
? current
: next
);
Because it loops once over the list.
You can use .DefaultIfEmpty(null) for preventing empty list exception.

Using a nested foreach to store one foreach value into an array

Alright so I didn't really know how to word this question, but I did my best. The goal I am trying to accomplish is to go through categories using a foreach loop. Inside the category foreach loop another foreach loop will go through Numbers. Right now it is grabbing ever value in the tables and storing them into an array. My goal is to only store the highest number in each category into the array.
Here is how the tables would look:
Category Table
Title NumberId
Type 1
Priority 2
Likelihood 3
Numbers Table
Order NumberId
3 1
2 1
1 1
3 2
2 2
1 2
3 3
2 3
1 3
So my goal would be instead of storing every order value into the array. I would like to store the highest number according to each number id. So there array would include 3,3,3.
This is what I have that stores every number into an array:
int[] values = new int[count];
foreach(var x in Category)
{
foreach(var w in x.Numbers)
{
values[y] = w.Order;
y++;
}
}
Solution:
int[] values = new int[count];
foreach(var x in Category)
{
foreach(var w in x.Numbers)
{
values[y] = x.Numbers.Select(o => o.Order).Max();
y++;
break;
}
}
You can use IEnumerable.Max() :
foreach(var x in Category)
{
values[y] = x.Numbers.Select(o => o.Order).Max();
y++;
}
This can be accomplished relatively easily through LINQ as:
int[] values = new int[count];
foreach(var x in Category)
{
values.[y] = x.Numbers.OrderBy(w => w.Order).Reverse().First();
y++;
}
This orders the x.Numbers by their ascending order, reverses the order (to place the highest value first in the order), and then selects the first value.
Ensure with this method that you've actually got a value for x.Number, else you'll get an exception thrown by the .First() call.
If you're unable to use LINQ (e.g. if you're on .NET 2.0), then consider using a Dictionary with the Category as the key, and the highest Number as the value:
Dictionary<int, int> categoriesByHighestOrders = new Dictionary<int, int>();
foreach(var x in Category)
{
if (!categoriesByHighestOrders.Keys.Contains[x.SomeIndetifier])
categoriesByHighestOrders.Add(x.SomeIdentifier, 0);
foreach(var w in x.Numbers)
{
if (categoriesByHighestOrders[x.SomeIndetifier] < w.Order
categoriesByHighestOrders[x.SomeIndetifier] = w.Order;
}
}

Categories