I have a snippet as follow. Basically I would like to create a dictionary from the series I currently have. If I did it the long way, there was no problem, the code run fine and I got the expected results.
class Program
{
static void Main(string[] args)
{
List<int> series = new List<int>() { 1,2,3,4 };
Dictionary<int, List<int>> D = new Dictionary<int,List<int>>();
foreach (var item in series)
{
D.Add(item, seriesWithinSeries(item));
}
}
public static List<int> seriesWithinSeries(int seed)
{
return Enumerable.Range(0, seed).Where(x => x < seed).ToList();
}
}
How do I convert that into Linq? I have tried this:
D = series.Select(x=> { return new (x,seriesWithinSeries(x));}).ToDictionary<int,List<int>>();
But the compiler complaints I need a type for the new, which makes sense. However, I do not really know how to fix it. Please help.
ToDictionary doesn't have a parameterless version. You probably want this:
var result = series.ToDictionary(x => x, x => seriesWithingSeries(x));
So anonymous type is not needed here. But for the sake of a complete explanation here is a correct syntax with an anonymous type:
var result = series
.Select(x => new { Key = x, Value = seriesWithinSeries(x) })
.ToDictionary(pair => pair.Key, pair => pair.Value);
Related
I have a list of my class
List<Example> exampleList
Which already has all the data inside of it. I need to create a dictionary
Dictionary<string, List<Example>> exampleDictionary
The Key needs to be Example.Name and the value needs to Example
Here is my code below. The problem is Example.Name can be the same. I need to group by Name. I need to loop through my list and if the Name does not exist add new Key and Value otherwise add the Value to the Key. I know I am setting this up wrong but I can't seem to figure out the correct way of doing this.
foreach(var x in exampleList)
{
if(!exampleDictionary.ContainsKey(x.Name)
exampleDictionary.Add(x.Name, x)
else
exampleDictionary[x.Name] = x;
}
I know this code wouldn't build. I am not sure how to set this up.
You can use LookUp() extension method:
var lookup = exampleList.ToLookUp(e => e.Name);
This method returns a Lookup<string, Example>, a one-to-many dictionary that maps keys to collections of values.
But your code can be fixed grouping by Name and adding each group to exampleDictionary:
foreach (var g in exampleList.GroupBy(e => e.Name))
exampleDictionary.Add(g.Key, g.ToList());
Or
var exampleDictionary = exampleList.GroupBy(e => e.Name).ToDictionary(g => g.Key, g => g.ToList());
This should work
Dictionary<string, List<Example>> exampleDictionary = new Dictionary<string, List<Example>>();
foreach(var x in exampleList)
{
if(!exampleDictionary.ContainsKey(x.Name)) {
exampleDictionary[x.Name] = new List<Example>();
}
exampleDictionary[x.Name].Add(x);
}
You can also use ToDictionary extension method to achieve what you want:
Dictionary<string, List<Example>> exampleDictionary=exampleList.GroupBy(e => e.Name)
.ToDictionary(g => g.Key,g.ToList());
Basically the same as user469104 (+1)
List<Example> le = new List<Example>() { new Example("one"), new Example("one"), new Example("two") };
Dictionary<string, List<Example>> de = new Dictionary<string,List<Example>>();
foreach (Example e in le)
{
if (de.ContainsKey(e.Name))
de[e.Name].Add(e);
else
de.Add(e.Name, new List<Example>() { e });
}
I have a simple List<string> with colon delimited values.
Some values, however, may be the same before the colon, but different after. I need to merge these two values based on the last most value.
Example
name:john
surname:michael
gender:boy
name:pete
title:captain
would become
surname:michael
gender:boy
name:pete
title:captain
list = list.GroupBy(s => s.Split(':')[0].ToLower())
.Select(g => g.Last())
.ToList();
In general: Use a Dictionary --> you're using a List AS a dictionary.
I prefer LazyDictionarys that you can update without checking key existance but for a standard .Net Dict in pseudocode
dict = new Dictionary()
for each item in your_LIST
{
tmp = item.Split(':')
if dict.ContainsKey(tmp[0])
{
dict[tmp[0]] = tmp[1]
}
else
{
dict.Add(tmp[0],tmp[1])
}
}
ANd you have a dictionary, which is what you want, if you really want to then convet it back to a list then fine, but really you probably want this to be a dictionary 'all the way down'
It can be cone using linq
private string[] inputs = new string[]
{
"name:john",
"surname:michael",
"gender:boy",
"name:pete",
"title:captain",
};
private string[] expected = new string[]
{
"surname:michael",
"gender:boy",
"name:pete",
"title:captain",
};
private static List<string> FilterList(IEnumerable<string> src) {
return src.Select(s =>
{
var pieces = s.Split(':');
return new {Name = pieces[0], Value = pieces[1]};
}).GroupBy(m => m.Name)
.Select(g => String.Format("{0}:{1}", g.Key, g.Last().Value)).ToList();;
}
[TestMethod]
public void TestFilter() {
var actual = FilterList(inputs);
CollectionAssert.AreEquivalent(expected, actual);
}
I'm trying to wrap the results of a query with a class called QueryResultViewModel from a list of dynamic objects retrieved by LINQ. These contain a integer field called Worked. I should not use a non-dynamic type because depending on the query it has other fields. I tried that:
var query = new HoursQuery( .. parameters .. );
this.Result = new ObservableCollection<QueryResultViewModel>(
query.Execute().Select( x => new QueryResultViewModel( x.Worked )));
But I got "'object' does not contain a definition for 'Worked'" and I don't know If it can be fixed without changing query's return type.
The Execute code may be useful too:
var res = some_list.GroupBy(a => new { a.Employee, a.RelatedTask, a.Start.Month })
.Select(g => new { K = g.Key, Worked = g.Sum(s => s.Duration.TotalHours) });
EDIT: This worked great but maybe it's not very elegant.
public class HQueryDTO
{
public double Worked;
public object K;
}
public IEnumerable<dynamic> Execute()
{
var list = base.Execute();
return res = list.GroupBy(a => new { a.Employee, a.RelatedTask } )
.Select(g => new HQueryDTO { K = g.Key, Worked = g.Sum(s => s.Duration.TotalHours) });
}
Now that the result has a type it can be returned dynamic.
I'm assuming you get that error at compile-time, in which case simply introduce dynamic via a cast:
.Select(x => new QueryResultViewModel( ((dynamic)x).Worked ))
I assume that the signature of Execute is something like object Execute(). If you return dynamic, it should work.
In C# i have a List which contains numbers in string format. Which is the best way to count all this numbers? For example to say i have three time the number ten..
I mean in unix awk you can say something like
tempArray["5"] +=1
it is similar to a KeyValuePair but it is readonly.
Any fast and smart way?
Very easy with LINQ :
var occurrenciesByNumber = list.GroupBy(x => x)
.ToDictionary(x => x.Key, x.Count());
Of course, being your numbers represented as strings, this code does distinguish for instance between "001" and "1" even if conceptually are the same number.
To count numbers that have the same value, you could do for example:
var occurrenciesByNumber = list.GroupBy(x => int.Parse(x))
.ToDictionary(x => x.Key, x.Count());
(As noted in digEmAll's answer, I'm assuming you don't really care that they're numbers - everything here assumes that you wanted to treat them as strings.)
The simplest way to do this is to use LINQ:
var dictionary = values.GroupBy(x => x)
.ToDictionary(group => group.Key, group => group.Count());
You could build the dictionary yourself, like this:
var map = new Dictionary<string, int>();
foreach (string number in list)
{
int count;
// You'd normally want to check the return value, but in this case you
// don't care.
map.TryGetValue(number, out count);
map[number] = count + 1;
}
... but I prefer the conciseness of the LINQ approach :) It will be a bit less efficient, mind you - if that's a problem, I'd personally probably create a generic "counting" extension method:
public static Dictionary<T, int> GroupCount<T>(this IEnumerable<T> source)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
var map = new Dictionary<T, int>();
foreach (T value in source)
{
int count;
map.TryGetValue(number, out count);
map[number] = count + 1;
}
return map;
}
(You might want another overload accepting an IEqualityComparer<T>.) Having written this once, you can reuse it any time you need to get the counts for items:
var counts = list.GroupCount();
I'm trying to write a dynamic sort of command line processor where I have a dictionary with keys being possible parameters, and the member being an Action where the string is the text between the parameters passed on the command line. Want to be able to add parameters just by adding the params array, and writing the action in the dictionary.
Yes I realize this is a pointless exercise in overcomplicating implementation to simplify maintenance. Mostly just trying to stress myself to learn more linq.
Here's my dictionary:
private static Dictionary<string[], Action<string>> _commandLineParametersProcessor = new Dictionary<string[], Action<string>>()
{
{
new string[] {"-l", "--l", "-log", "--log"},
(logFile) =>
{
_blaBla.LogFilePath = logFile;
}
},
{
new string[] { "-s", "--s", "-server", "--server" },
(server) =>
{
ExecuteSomething(server);
_blaBla.Server = server;
}
}
};
What's the most elegant mechanism to take string[] args and not just correlate the members that fall within any of the dictionary key arrays, but Aggregate((x,y) => string.Format("{0} {1}", x, y)) the sequence of elements (was thinking TakeWhile() fits in here somehow) inbetween the args[] members that would be Contain()ed in any of the keys arrays, and handing them into the action of the respective key's value member.
We have all written these little command line processors countless times, and while obviously a simple loop and switch is always more than adequate, this is again as I said an exercise trying to stress my linq skills. So please no complaints that I'm overengineering, that part is obvious.
Update:
To make this maybe a little easier, here is a non-linq way of doing what I'm looking for (may be imperfect, this is just winging it):
Action<string> currentAction;
string currentActionParameter;
for(int i = 0; i < e.Args.Length; i++)
{
bool isParameterSwitch = _commandLineParametersProcessor.Keys.Any((parameterChoices) => parameterChoices.Contains(e.Args[i]));
if (isParameterSwitch)
{
if (!string.IsNullOrEmpty(currentActionParameter) && currentAction != null)
{
currentAction(currentActionParameter);
currentAction = null;
currentActionParameter = "";
}
currentAction = _commandLineParametersProcessor[_commandLineParametersProcessor.Keys.Single((parameterChoices) => parameterChoices.Contains(e.Args[i]))];
}
else
{
currentActionParameter = string.Format("{0} {1}", currentActionParameter, e.Args[i]);
}
}
This is not an altogether bad approach, I just wonder if anyone can maybe simplify it a little using linq or otherwise, though this may be the simplest form i guess..
Borrowing half of Adam Robinson's answer (+1 btw), but realizing that the Dictionary will never be accessed by key, and you just want to run the Actions instead of building up a string...
var inputCommands = args
.Select((value, idx) => new { Value = value, Group = idx / 2 })
.GroupBy(x => x.Group)
.Select(g => new
{
Command = g.First().Value,
Argument = g.Last().Value
}).ToList();
inputCommands.ForEach(x =>
{
Action<string> theAction =
(
from kvp in commands
where kvp.Key.Contains(x.Command)
select kvp.Value
).FirstOrDefault();
if (theAction != null)
{
theAction(x.Argument);
}
}
kvp.Key.Contains really defeats the whole point of Dictionary. I'd re-design that to be a Dictionary<string, Action<string>>. Then you could say
inputCommands.ForEach(x =>
{
if (commands.ContainsKey(x.Command))
{
commands[x.Command](x.Argument);
}
}
PS: I can recall much more obtuse C# code that I have written than this.
I must admit the possibility that you want to collect the actions, instead of running them. Here is that code:
var todo =
(
from x in inputCommands
let theAction =
(
from kvp in commands
where kvp.Key.Contains(x.Command)
select kvp.Value
).FirstOrDefault()
where theAction != null
select new { TheAction = theAction, Argument = x.Argument }
).ToList();
Assuming you know that every command has a corresponding argument (so 'args' will always be in the format of
cmd arg (repeated)
You could do something ridiculous like this...
var output = args.Select((value, idx) => new { Value = value, Group = idx / 2 })
.GroupBy(x => x.Group)
.Select(g => new
{
Command = commands.FirstOrDefault(kvp =>
kvp.Key.Contains(g.First().Value)).Value,
Argument = g.Last().Value
})
.Where(c => c.Command != null)
.Aggregate(
new StringBuilder(),
(builder, value) =>
{
builder.AppendLine(value.Command(value.Argument));
return builder;
}).ToString();
But that is, frankly, the most obtuse bit of C# that I can recall ever writing, and not a very good way to teach yourself LINQ. Nonetheless, it will do what you're asking.
EDIT
Just realized (thanks to David B) that your key is a string[], not just a string, so I added some even more obtuse code that deals with that.