How to create dictionary<int, string> from IEnumearble<IEnumerable<int, string>> - c#

have a complex Linq expression right here. At the moment I'm only able to create IEnumearble, but I need to parse to IEnumerable<int, string>. I have no clue how to take that 'string'.
IEnumerable<IEnumerable<int>> uniqueColumns = test
.Where(e => e.ToolParameters != null)
.Select(x => x.ToolParameters.Select(u => u.ToolParameterTypeId))
.Distinct();
uniqueColumnIds = uniqueColumns
.SelectMany(a => a)
.Distinct();
As you can see, I check if 'ToolParameters' is null. If it is not, then I select ' ToolParametersTypeId', but I also need to select 'ToolParameteresTypeName', but have no idea how...
After that, I need to parse that Ienumearble<Ienumearble<>> to only one Ienumerable because my goals is to have unique values from a bunch of lists. But I need to make a dictionary which consists of unique key,string values from a bunch of lists...
I have uniqueColumnIds, but I also need to get uniqueColumnNames and put them together to get a dictionary of key,value pairs. Maybe someone has any ideas on how to do that?

Dictionary is not the correct structure, as each key can only appear once. If a ToolParametersTypeId has more than one corresponding ToolParameteresTypeName then you will need to discard all but one ToolParameteresTypeName. A more appropriate structure may be IEnumerable<(int, string)>:
IEnumerable<(int ToolParameterTypeId, string ToolParameteresTypeName)> uniqueColumns =
test
.Where(e => e.ToolParameters != null)
.SelectMany(e => e.ToolParameters.Select(tp =>
(tp.ToolParameterTypeId, tp.ToolParameteresTypeName)))
.Distinct();
SelectMany flattens the nested IEnumerables, and the nested Select projects each item into a ValueTuple.
Using Distinct on an IEnumerable<ValueTuple> then checks for equality based on the value of each tuple component, not by reference, so you will end with distinct pairs of ToolParameterTypeId, and ToolParameteresTypeName.

It is easy.
IEnumerable<IEnumerable<(int key, string value)>> target = default; // replace default.
var dict = target.SelectMany(x => x).ToDictionary(x => x.key, x => x.value);

Related

LINQ - grouping by name to Dictionary<string, List<T>>

I am building a library app. I have a list of Books where some of them have a duplicate name (there are few copies of the same book). I would like to convert the list to Dictionary>, where the string would be the name of a book, and the List would contain all the Book objects with this name.
I've managed to get this far:
var result = queriedBooks
.GroupBy(b => b.Name)
.Where(g => g.Count() >= 1)
.ToDictionary(b => b.Key, /// );
This is where I get stuck. I have no idea what to pass as a value. Intellisense does not help either, as there is no Value property available. I would like to avoid using anonymous objects, as each Book entry has many properties which I use in a view.
Thank you very much!
As an alternative you may want just Lookup<String, Book> instead of combersome Dictionary<String, List<Book>>:
LookUp<String, Book> result = queriedBooks
.ToLookup(book => book.Name);
In case of Dictionary<String, List<Book>>:
var result = queriedBooks
.GroupBy(book => book.Name)
.ToDictionary(chunk => chunk.Key, chunk => chunk.ToList());
Please note that .Where(g => g.Count() >= 1) is redundant;
You should simply use ToList() like this:
.ToDictionary(b => b.Key, b => b.ToList());
Each group has a Key property which is the key. It also (the group) is an IEnumerable<Book> that represents the items in the group which is why ToList() works.
try with ToList with distinct for example In a table, a column may contain many duplicate values; and sometimes you only want to list the different (distinct) values.
var query = queriedBooks
.Distinct()
.GroupBy(b => b.Name)
.ToDictionary(b => b.Key, b.ToList() );
please don't use it .Where(g => g.Count() >= 1) it is redundant

c# - Linq Query to retrieve all objects with a max value

Currently I have a List of objects in which I need to find all occurrences that have the maximum value.
Currently my solution to this has been:
Foo maxFoo = list.OrderByDescending(foo => foo.A).First();
List<Foo> maxFoos = new List<Foo>();
foreach(Foo foo in list) {
if (foo.A.Equals(maxFoo.A)) {
maxFoos.Add(foo);
}
}
However I want to know if there is a way to do this in a single Linq expression.
All the resources I have read only refer to getting the max value for one object.
Note: For the time being, I want to know a solution which doesn't rely on MoreLinq
You can group by the property, then order the groups by key, and take the content of the first one, like this:
var res = list
.GroupBy(item => item.A)
.OrderByDescending(g => g.Key)
.First()
.ToList();
You could group by A, order the group, and get the elements in the first group, which corresponds to the elements with the max value of A:
list
.GroupBy(x => x.A)
.OrderByDescending(grp=> grp.Key)
.First()
.Select(x => x);
This works:
var maxFoos =
list
.OrderByDescending(foo => foo.A)
.GroupBy(foo => foo.A)
.Take(1)
.SelectMany(foo => foo)
.ToList();

Use LINQ to combine a property in a list of lists?

I have a Dictionary that looks like such: Dictionary<Search_Requests, List<Tuple<Search_Subjects, SearchData>>>
In the SearchData class, there's a property called SearchCode. What I want to do is get an array of every search code that appears in this dictionary. I could do this with a few loops, but I'd really prefer to use LINQ. Unfortunately, I can't wrap my mind around how to do this. I tried
RequestDictionary.Select(s => s.Value.Select(z => s.Value.Select(x => x.Item2.SearchCode).ToArray()).ToArray()).ToArray();
But that just got me a string[][][], which isn't close to what I wanted. Can I get a push in the right direction?
You can use .SelectMany() to flatten the results:
RequestDictionary
.SelectMany(s
=> s.Value.SelectMany(z => s.Value.Select(x => x.Item2.SearchCode))
.ToArray();
The trick is to combine .Select() and .SelectMany():
var codes = requestDictionary
//Extract all List<>s from the dictionary and enumerate them back-to-back:
.SelectMany(entry => entry.Value)
//Extract the SearchCode from each list item:
.Select(tuple => tuple.Item2.SearchCode)
.ToArray();

Remove item from dictionary where value is empty list

What is the best way to remove item from dictionary where the value is an empty list?
IDictionary<int,Ilist<T>>
var foo = dictionary
.Where(f => f.Value.Count > 0)
.ToDictionary(x => x.Key, x => x.Value);
This will create a new dictionary. If you want to remove in-place, Jon's answer will do the trick.
Well, if you need to perform this in-place, you could use:
var badKeys = dictionary.Where(pair => pair.Value.Count == 0)
.Select(pair => pair.Key)
.ToList();
foreach (var badKey in badKeys)
{
dictionary.Remove(badKey);
}
Or if you're happy creating a new dictionary:
var noEmptyValues = dictionary.Where(pair => pair.Value.Count > 0)
.ToDictionary(pair => pair.Key, pair => pair.Value);
Note that if you get a chance to change the way the dictionary is constructed, you could consider creating an ILookup instead, via the ToLookup method. That's usually simpler than a dictionary where each value is a list, even though they're conceptually very similar. A lookup has the nice feature where if you ask for an absent key, you get an empty sequence instead of an exception or a null reference.
Alternative provided just for completeness.
Alternatively (and depending entirely on your usage), do it at the point of amending the list content on the fly as opposed to a batch at a particular point in time. At a time like this it is likely you'll know the key without having to iterate:
var list = dictionary[0];
// Do stuff with the list.
if (list.Count == 0)
{
dictionary.Remove(0);
}
The other answers address the need to do it ad-hoc over the entire dictionary.

Remove duplicates of a List, selecting by a property value in C#?

I have a list of objects that I need some duplicates removed from. We consider them duplicates if they have the same Id and prefer the one whose booleanValue is false. Here's what I have so far:
objects.GroupBy(x => x.Id).Select(x => x.Where(y => !y.booleanValue));
I've determined that GroupBy is doing no such grouping, so I don't see if any of the other functions are working. Any ideas on this? Thanks in advance.
You can do this:
var results =
from x in objects
group x by x.Id into g
select g.OrderBy(y => y.booleanValue).First();
For every Id it finds in objects, it will select the first element where booleanValue == false, or the the first one (if none of them have booleanValue == false).
If you prefer fluent syntax:
var results = objects.GroupBy(x => x.Id)
.Select(g => g.OrderBy(y => y.booleanValue).First());
Something like this should work:
var result =
objects.GroupBy(x => x.Id).Select(g =>
g.FirstOrDefault(y => !y.booleanValue) ?? g.First())
This assumes that your objects are of a reference type.
Another possibility might be to use Distinct() with a custom IEqualityComparer<>.
This partially answers the question above, but I justed need a really basic solution:
objects.GroupBy(x => x.Id)
.Select(x => x.First())
.ToArray();
The key to getting the original object from the GroupBy() is the Select() getting the First() and the ToArray() gets you an array of your objects, not a Linq object.

Categories

Resources