I have a resource file I grab like this:
var rs = <somewhere>.FAQ.ResourceManager
.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
and I want to parse it into a dictionary of dictionaries but I can't figure out quite how. this is what I'm trying:
var ret = rs.OfType<DictionaryEntry>()
.Where(x => x.Key.ToString().StartsWith("Title"))
.ToDictionary<string, Dictionary<String, string>>(
k => k.Value.ToString(),
v => rs.OfType<DictionaryEntry>()
.Where(x => x.Key.ToString().StartsWith(v.Value.ToString().Replace("Title", "")))
.ToDictionary<string, string>(
key => key.Value,
val => val.Value
)
);
so if I understand this correctly, k should refer to a DictionaryEntry and thus I should be able to dereference it like k.Value and to manufacture my dictionary in each of the outer dictionary's entries I do another query against the resource file, thus key and val should also be of type DictionaryEntry.
In referencing val.Value I get the error "Cannot choose method from method group. Did you intend to invoke the method?" though that should be a property, not a method.
help?
p.s. as an explanation, my resource file looks sort of like this:
TitleUser: User Questions
TitleCust: Customer Questions
User1: Why does something happen? Because…
User2: How do I do this? Start by…
Cust1: Where can I find…? It is located at…
Cust2: Is there any…? yes, look for it…
which means I first get a list of sections (by looking for all keys that start with "Title") and for each I look for a list of questions
so the answer turns out to be that the compiler knows better as to the types involved. leaving out the specifiers makes it work, though quite why my specifiers were wrong I don't yet get.
var ret = rs.OfType<DictionaryEntry>()
.Where(x => x.Key.ToString().StartsWith("Title"))
.ToDictionary(
k => k.Value.ToString(),
v => rs.OfType<DictionaryEntry>()
.Where(x => x.Key.ToString().StartsWith(v.Key.ToString().Replace("Title", "")))
.ToDictionary(
x => x.Value.ToString().Split('?')[0] + "?",
x => x.Value.ToString().Split('?')[1]
)
);
(I've made some changes to actually make it do what I intended for it to do).
Related
Looking for someone to help me with C#, LINQ.
I have a Dictionary<int,int> that I am ordering like so: .OrderBy(_ => _.Value).ThenBy(_ => ThisMethodReturnsAnotherIReadOnlyDict<int,int>()).ThenByDescending(_ => _.Key).
What I want is to order the first dictionary by its value and then if there are still equal values I want that tie to be broke by the ThisMethodReturnsAnotherIReadOnlyDict<int,int>(). This first key/value of this ThisMethodReturnsAnotherIReadOnlyDict to break the tie and be on top. And finally, if everything fails, then order by it's key descending.
Some data for this like:
(First Dictionary)
[1,400]
[2,550]
[3,200]
[4,200]
(Second dictionary)
[3,50]
[4,140]
[2,600]
[1,700]
For this scenario I want my ordering to return: [3,50]
Can anyone help please?
Thanks!
It looks like you're looking for something like this:
var firstDict = new Dictionary<int, int>() {
{1,400},
{2,550},
{3,200},
{4,200}
};
var secondDict = new Dictionary<int, int>() {
{3,50},
{4,140},
{2,600},
{1,700}
};
var result = (from kvp in firstDict
join tieBreaker in secondDict on kvp.Key equals tieBreaker.Key
select new { kvp.Key, V1 = kvp.Value, V2 = tieBreaker.Value })
.OrderBy(x => x.V1)
.ThenBy(x => x.V2)
.ThenByDescending(x => x.Key)
.First();
This will join the first and second dictionaries together by its keys and will, respectively, order by the value of the first dictionary, the value of the second dictionary and then descending by the key itself.
How about:
var ans = firstDict
.OrderBy(kv => kv.Value)
.ThenBy(kv => ThisMethodReturnsAnotherIReadOnlyDict<int,int>().TryGetValue(kv.Key, out var val2) ? val2 : kv.Key)
.ToList();
Unless ThisMethodReturnsAnotherIReadOnlyDict<int,int> may change, you may want to cache the return value in a variable before sorting.
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);
I have a file with a simple key,value format, one per line.
e.g:
word1,filepath1
word2,filepath2
word3,filepath5
I'm trying to read this into a Dictionary<string,string> in one go with LINQ. There are some duplicates in the file (where the first part - the first string - is the duplicate). In this case, I'm ok with dropping the duplicates.
This is my LINQ which isn't working:
var indexes = File.ReadAllLines(indexFileName)
.Select(x => x.Split(','))
.GroupBy(x=>x[0])
.ToDictionary(x => x.Key, x => x.ElementAt(1));
The ToDictionary part is confusing me, how do I retrieve the first value from the group and assign it to the value of the dictionary?
I get a System.ArgumentOutOfRangeException: 'Specified argument was out of the range of valid values.' exception.
var indexes = File.ReadAllLines(indexFileName)
.Select(x => x.Split(','))
.GroupBy(x => x[0])
.ToDictionary(x => x.Key, x => x.First()[1]);
So the problem here is that you're grouping arrays, not strings. Therefore the group objects you're dealing with in the ToDictionary() lambda are enumerations of arrays, not of strings. g.ElementAt(0) isn't a string. It's the first array of strings:
When
g.Key == "word1"
then g.ElementAt(0) is...
{ "word1", "filepath1" }
So you want g.ElementAt(0).ElementAt(1), or g.First()[0], or something to that effect.
That seems painfully obvious in hindsight, but unfortunately only in hindsight, for me.
I would suggest that after you accept Matthew Whited's answer, you clarify the code by turning the split lines into anonymous objects as soon as you can. ElementAt(1) doesn't communicate much.
var indexes =
File.ReadAllLines(indexFileName)
.Where(s => !String.IsNullOrEmpty(s))
.Select(x => x.Split(','))
// Turn the array into something self-documenting
.Select(a => new { Word = a[0], Path = a[1] })
.GroupBy(o => o.Word)
.ToDictionary(g => g.Key, g => g.First().Path)
;
Converting each line to an object makes it easier for me to think about, and Intellisense starts playing on your team as well.
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.
I would like to know whether there is any way to shorten a comparison in lambdas by using arrays containing the comparison elements, instead of writing the elements one by one.
In practice, I have a Dictionary<K,V> variable named litemList already filled with data. I would like to have another Dictionary<K,V> variable with just some of the Keys of litemList.
lfilteredItemlist = litemList.Where(m => m.Key == "Name", m.Key == "Surname")
.ToDictionary(m => m.Key, m => m.Value);
This code works perfectly but when I have 10 or more Keys to filter and they might change with time (or even selected by the users), this solution is not feasible.
I am looking for some solution where, assuming there is an array withall the Keys to filter, I can use something like this:
filterArray = {"Name", "Surname"};
lfilteredItemlist = litemList.Where(m => m.Key == filterArray)
.ToDictionary(m => m.Key, m => m.Value);
I am quite sure that there is a method because once I saw it when looking for material about Dynamic LINQ. Unfortunately I cannot find the article again and Scott Guthrie does not mention it in his blog.
Thanks
Francesco
How about changing the code to this:
lfilteredItemlist = litemList.Where(m => filterArray.Contains(m.Key))
.ToDictionary(m => m.Key, m => m.Value);