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

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

Related

Find the Biggest List in a Dictionary of Lists

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;

Find the first free id

One of my small database management projects (written in delphi) used sql queries to find the first free id of mysql table.
Example: I have to find the first free id (hole) in a table like this:
| id | Col1 |
|------|------|
| 5101 | ABC |
| 5102 | BCD |
| 5103 | CDE |
| 5105 | EFG | 🡔 first missing id
| 5106 | GHI |
| 5108 | ILM |
The code should find the first free id 5104
Here's how I'd do it in SQL (in old project):
SELECT
MIN((doc.id + 1)) AS nextID
FROM (doc
LEFT JOIN doc doc1
ON (((doc.id + 1) = doc1.id)))
WHERE (ISNULL(doc1.id) AND (doc.id > 5000))
Now, which I am rewriting in c # language, I need to convert sql statements into a LINQ query (which uses Devart dotConnect for mysql Entity Framework).
Starting from here:
DC db = new DC();
var nums = db.Documentos.OrderBy(x => x.Id);
From Can LINQ be used to find gaps in a sorted list?:
var strings = new string[] { "7", "13", "8", "12", "10", "11", "14" };
var list = strings.OrderBy(s => int.Parse(s));
var result = Enumerable.Range(list.Min(), list.Count).Except(list).First(); // 9
Basically, order the list. Then create an array of sequential numbers (1,2,3...) from the minimum all the way to the max. Check for missing values in the list, and grab the first one. That's the first missing number.
This can give you all gaps within your table
var nums= (new List<int> (){1,2,3,25,4,5,6,7,8, 12, 15,21,22,23}).AsQueryable();
nums
.OrderBy(x => x)
.GroupJoin(nums, n=> n + 1, ni => ni, (o,i)=> new {o, i})
.Where(t=> !(t.i is IGrouping<int, int>))
.Dump();
.Net Fiddle
Another method (similar to what you're using now).
Assume you have an array of integers (or another type of collection) like this:
var myIDs = new int[] { 5101, 5113, 5102, 5103, 5110, 5104, 5105, 5116, 5106, 5107, 5108, 5112, 5114, 5115 };
If it's not already ordered, the OrderBy() it:
myIDs = myIDs.OrderBy(n => n).ToArray();
Extract the first number that is less than (next number) + 1:
int result = myIDs.Where((n, i) => (i < myIDs.Length - 1) && (n + 1 < myIDs[i + 1])).FirstOrDefault();
If none of the members of this collection satisfy the condition, take the last one and add 1:
result = result == default ? myIDs.Last() + 1 : result;

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.

Linq How to combine two List's columns

Please Help me in the following...
I have two list objects as follows:
list1:
ID col1
--------
1 A
1 B
1 C
list2:
ID col2
--------
1 D
1 E
1 F
Now I want:
ID col1 col2
---------------
1 A D
1 B E
1 C F
So basically column1 then column 2 from list1 then column 3 from list 2. Column1 is common.
Please note that the number of rows may not be always same.. in that case it will be null.
I really really need this solution in Linq. Thanks.
List<Class> list1 = new List<Class>();
List<Class> list2 = new List<Class>();
// Add classes to lists...
list1.AddRange(list2);
// Order merged list...
list1.OrderByDescending(o => o.col1).ThenBy(o => o.col2);
Trying to understand...
Dictionary<Int32, Class[]> dictionary = new Dictionary<Int32, Class[]>();
list2.Reverse();
for (Int32 i = 0; i < list1.Count; ++i)
dictionary[i] = new Class[2] { list1[i], list2[i] };
I really don´t understand why was hard for get clear the question, he only want have two array combined in one (still i don't know why in the aswers of the web you only find Concat,AddRange or Union. Wrong Answers For this Question):
I solve it with Zip:
var result = list1.Zip(list2,(first,second)=>new {entrada=first,salida=second});
Now You Can do Something like this:
var union=result.Select(x=> new {x.entrada, x.salida, horas = int.Parse((DateTime.Parse(x.salida).Subtract(DateTime.Parse(x.entrada))).Hours.ToString()) });

Categories