Flatten a C# Dictionary of Lists with Linq - c#

I have a Dictionary in C#:
Dictionary<string, List<string>>
How can I use Linq to flatten this into one List<string> that contains all of the lists in the Dictionary?
Thanks!

Very easily:
var list = dictionary.Values // To get just the List<string>s
.SelectMany(x => x) // Flatten
.ToList(); // Listify
Here the SelectMany call takes a sequence of inputs (the lists which make the values of the dictionary) and projects each single input into another sequence of outputs - in this case "the elements of the list". It then flattens that sequence of sequences into a single sequence.

as a query
var flattened = from p in dictionary
from s in p.Value
select s;
or as methods...
var flattened = dictionary.SelectMany(p => p.Value);
I like this over what others have done as I'm passing the whole dictionary into the Linq query rather than just the values.

SelectMany is the easiest way to flatten things:
Dictionary.Values.SelectMany(x => x).ToList()

Assuming you have an instance called dict:
dict.SelectMany(pair => pair.Value.Select(str => str));

You should try something like this:
dict.Values.Aggregate(new List<String>(), (a, b) => a.Concat(b));

Related

LINQ query to find items in a list containing substring elements from a second list

I am trying to list all elements from the first list where it contains a substring equal to all elements from the second list
First list:
C:\Folder\Files_01026666.pdf
C:\Folder\Files_01027777.pdf
C:\Folder\Files_01028888.pdf
C:\Folder\Files_01029999.pdf
Second list:
01027777
01028888
List result should be:
C:\Folder\Files_01027777.pdf
C:\Folder\Files_01028888.pdf
the closer that I got was with .Intersect() but both string-element should be equals
List<string> resultList = firstList.Select(i => i.ToString()).Intersect(secondList).ToList();
List<string> resultList = firstList.Where(x => x.Contains(secondList.Select(i=>i).ToString()));
List<string> resultList = firstList.Where(x => x == secondList.Select(i=>i).ToString());
I know I can do this another way but I'd like to do it with LINQ.
I have looked at other queries but I can find a close comparison to this with Linq. Any ideas or anywhere you can point me to would be a great help.
We can use EndsWith() with Path.GetFileNameWithoutExtension(), as strings in the secondList are not entire file names.
var result = firstList
.Where(path => secondList.Any(fileName => Path.GetFileNameWithoutExtension(path).EndsWith(fileName)));
Try Online
var q = list1.Where(t=>Regex.IsMatch(t,String.Join("|",list2.ToArray()))));
Seems to work for lists of strings. Using Regex can be problem in LINQ. This won't work in Linq2SQL for example.

How can i split and get distinct words in a list?

My sample data coloumn, which come from an CSV file is
|----Category------------|
SHOES
SHOES~SHOCKS
SHOES~SHOCKS~ULTRA SOCKS
I would love to split the specific column and get the distinct values in a list like
SHOES
SHOCKS
ULTRA SOCKS
I tried the following, but it does not work as expected.
var test = from c in products select c.Category.Split('~').Distinct().ToList();
It actually returns the following.
Any thoughts please? Thank you.
I would use SelectMany to "flatten" the list before removing duplicates:
products.SelectMany(c => c.Category.Split('~'))
.Distinct()
You can use SelectMany to flatten the collection:
products.SelectMany(p => p.Category.Split('~')).Distinct().ToList();
You were close, you just needed to flatten out your collection to pull the individual items of each grouping via a SelectMany() call :
// The SelectMany will map the results of each of your Split() calls
// into a single collection (instead of multiple)
var test = products.SelectMany(p => p.Category.Split('~'))
.Distinct()
.ToList();
You can see a complete working example demonstrated here and seen below :
// Example input
var input = new string[] { "SHOES","SHOES~SHOCKS","SHOES~SHOCKS~ULTRA SOCKS" };
// Get your results (yields ["SHOES","SHOCKS","ULTRA SOCKS"])
var output = input.SelectMany(p => p.Split('~'))
.Distinct()
.ToList();
Merge this list of list of strings into a single list by using SelectMany() and Just add another Distinct to your List..
var test = from c in products select c.Category.Split('~').Distinct().ToList().SelectMany(x => x).Distinct().ToList();
Here's how you'd do it in query syntax.
var test = (from p in products
from item in p.Category.Split('~')
select item).Distinct().ToList();

Working with list of tuples: calculating number of items

I have the following code working with Tuples. Input is list of items, output is list of tuples and we need to calculate number of items for each date basically.
List<Tuple<DateTime, int>> list = new List<Tuple<DateTime, int>>();
foreach (ItemClass item in items)
{
foreach(Tuple<DateTime, int> tuple in list)
{
if (tuple.Item1 == item.date)
{
tuple.Item2++;
continue;
}
}
list.Add(Tuple.Create<DateTime, int>(item.date, 1));
}
This code currently doesn't compile because Item2 is read-only, the question is how to make it work?
Earlier this worked with the Dictionary but I had to remove it because it was not acceptable for outer code to work with the Dictionary.
Tuples are not intended for use in scenarios where mutability is required. You could make your own class that combines a DateTime with a mutable integer counter, but you can also do it with LINQ, converting to a list of tuples at the very end:
var list = items
.GroupBy(item => item.date)
.Select(g => Tuple.Create(g.Key, g.Count()))
.ToList();
The above code creates a group for each date, and then produces tuples only when the final counts of items in each group are known.
Try using Linq, GroupBy()to group by date, then use Select() and create a tuple for each group and finally convert to a list using ToList(). Something like
var result = items.GroupBy(x => x.Date)
.Select(x => Tuple.Create(x.Key, x.Count()))
.ToList();
I'm assuming because it's read only it already has a property, I think I've used tuple before so yeah, it probably does.
maybe you can't edit it because you can edit iterators in the Foreach() loop, perhaps experiment with another kind of loop.
OR
Set the item2 object to an object outside of the current loop and use that instead of the iterator.

Lambda expression for getting items from list according to indexes

Is it possible to get objects from a list according to their indexes at one shot? For example I have a List<string> alist. I have an integer List List<int> indexes which has indexes. Is it possible to get a result list from the original list which equals the indexes in the array.
I am looking for something like List<string> resultlist = alist.GetItems(items.indexin(indexes)) (that's just my imagination, not the actual syntax-sorry)
Something like this should work:
var result = indexes.Select(i => alist[i]).ToList();
Of course, I recommend you make it a bit more robust.
var result = alist.Where((theString, theIndex) => indexes.Contains(theIndex));
indexes.Select<int, string>(i => alist[i]).ToList<string>();

Nested lists, how I can do this with lambda expression?

Can't really understand how the select extension method works with a list inside another list, like this:
var queries = (from item in list
from item2 in list.anotherlist
select item2).ToList<MyType>();
This will not work:
// Gives me a list of List<QueryResult>
var queries = list.Select(item => item.anotherlist).ToList();
The SelectMany operator ought to do the trick - in this case, it takes a list of lists and flattens it:
var queries = list.SelectMany(sublist => sublist).ToList();
use selectmany
var queries = list.SelectMany(l => l.anotherList).ToList();

Categories