Is there ToSortedDictionary in Linq? [duplicate] - c#

This question already has answers here:
Building a sorted dictionary using ToDictionary
(3 answers)
Closed 5 years ago.
I am refactoring a code like this:
var result = new SortedDictionary<int, string>();
foreach (var item in foo)
{
result[item.id] = item.name;
}
foreach (var item in bar)
{
result[item.id] = item.name;
}
return result;
I would like to write:
return foo.Concat(bar).ToSortedDictionary(i => i.id, i => i.name);
but I did not find it in Linq?

First solution is to prepare Dictionaryand use as an argument to create a SortedDictionary:
return new SortedDictionary<T1, T2>(foo.Concat(bar).ToDictionary())
Another option is to write an extension method like this:
public static SortedDictionary<K, V> ToSortedDictionary<K,V>(this Dictionary<K, V> existing)
{
return new SortedDictionary<K, V>(existing);
}

You can use return new SortedDictionary<T1, T2>(foo.Concat(bar).ToDictionary()); or you can write your own extension method.
As to why it doesn't exist, there's plenty of similar methods that don't exist- the basics are provided and whatever else you need you can easily make yourself.

Related

OrderedDictionary value not returning list but object [duplicate]

This question already has answers here:
No generic implementation of OrderedDictionary?
(13 answers)
Closed 1 year ago.
Ok, I give up. It's probably something really simple I'm missing but I've been stuck on this for the last 2 hours and I can't find the answer anywhere online. The below code shows a CS1579 error in my list inside my foreach saying that:
"foreach statement cannot operate on variables of type 'object' because 'object' does not contain a public definition for 'GetEnumerator'".
Shouldn't my roomList[roomNameTest] return a List<string>?
var roomList = new OrderedDictionary();
var listA = new List<string>();
listA.Add("elemA");
listA.Add("elemB");
roomList["roomA"] = listA;
var roomNameTest = "roomA";
if (roomList.Contains(roomNameTest))
{
var list = roomList[roomNameTest];
foreach (var item in list)
{
Console.WriteLine(item);
}
}
SOLUTION:
Using a Dictionary<string, List<string>>() worked really well and I used the OrderBy(x => x.Key) to sort the dictionary later on as I needed. Thanks everybody for the contribution, much appreciated.
OrderedDictionary isn't a generic class so it works with objects only. You will need to cast or use a different type of collection. For example:
var list = (List<string>) roomList[roomNameTest];
But that might lead to issues if you add something that is not a <List<string> to the dictionary.
Also, I'm not really sure that you need to use OrderedDictionary here, and a strongly typed Dictionary<string, List<string>> would be much better. For example:
var roomList = new Dictionary<string, List<string>>();
//...
if (roomList.ContainsKey(roomNameTest))
{
//...
}
Though I would also recommend using TryGetValue:
if(roomList.TryGetValue(roomNameTest, out var list))
{
foreach (var item in list)
{
Console.WriteLine(item);
}
}
Well, since items of OrderedDictionary declared being of type object, .Net treats them as
instances of object, which don't imeplement IEnumerable. For instance you can easily put
roomList.Add("abc", 123);
roomList.Add("def", true);
roomList.Add("pqr", "bla-bla-bla");
You can try casting these items
into IEnumerable<string> and on success looping:
var roomList = new System.Collections.Specialized.OrderedDictionary();
var listA = new List<string>();
listA.Add("elemA");
listA.Add("elemB");
// Note "Add", since item with Key == "roomA" doesn't exist
roomList.Add("roomA", listA);
var roomNameTest = "roomA";
if (roomList.Contains(roomNameTest)) {
// if item implements IEnumerable<string>, say it List<string>
// we can loop over it
if (roomList[roomNameTest] is IEnumerable<string> list)
foreach (var item in list) {
Console.WriteLine(item);
}
}

Extension method on Item in List within another List [duplicate]

This question already has answers here:
Flatten List in LINQ
(5 answers)
Closed 6 years ago.
I'm trying to perform an run an extension method on every item within a List<> that is inside another List<> to return collection of a given type (returned by the extension method).
I initially tried (and failed) to do this using linq, but I have the following:
var dataset = GetReportDataset(org);
var reportData = new List<InterventionAndNeetRiskReportLineModel>();
foreach (var record in dataset)
{
foreach (var inter in record.InterventionHistory)
{
reportData.Add(inter.ToInterventionAndNeetRiskReportLineModel());
}
}
return _reportWriter.ReportCsvStream(reportData);
So my question is, how can I project the result of my extension method for each item in the child collection using linq?
UPDATE ToInterventionAndNeetRiskReportLineModel() extension method
public static InterventionAndNeetRiskReportLineModel ToInterventionAndNeetRiskReportLineModel(this InterventionHistory intervention)
{
return new InterventionAndNeetRiskReportLineModel()
{
Beneficiary = intervention.Person.Beneficiary,
CourseTitle = intervention.CourseTitle,
CaseNotes = intervention.CaseNotes,
EndDate = intervention.EndDate?.ToString(),
StartDate = intervention.StartDate.ToString(),
ParticipantId = intervention.Person.ParticipantId,
FirstEit = intervention.Person.EitScores.GetFirstEitReading().ToString(),
LastEit = intervention.Person.EitScores.GetLastEitReading().ToString(),
FirstLpt = intervention.Person.LptScores.GetFirstLptReading().ToString(),
LastLpt = intervention.Person.LptScores.GetLastLptReading().ToString(),
Gender = intervention.Person.Equalitites.Gender,
HoursAttended = intervention.NoOfHours.ToString(),
LanguageOfDelivery = intervention.DeliveryLanguage,
Providername = intervention.ProviderName,
QanCode = intervention.QanCode,
SchoolCollegeName = intervention.ProviderName
};
}
I'm not completely sure which part of the question code you want to separate into an extension method. Also, don't be to focused on the extension method part, its nothing different from other functions, as far as the writing is concerned.
You can use SelectMany in order to get a flat list of InterventionHistory objects and Select in order to convert to InterventionAndNeetRiskReportLineModel and ToList for the final result as list instead of IEnumerable<T> if you really need that.
var reportData = GetReportDataset(org)
.SelectMany(r => r.InterventionHistory)
.Select(i => i.ToInterventionAndNeetRiskReportLineModel())
.ToList();
So, maybe you want an extension method like
public static IEnumerable<InterventionAndNeetRiskReportLineModel> ToInterventionRiskReports(this IEnumerable<ReportDataset> _self)
return _self
.SelectMany(r => r.InterventionHistory)
.Select(i => i.ToInterventionAndNeetRiskReportLineModel());
}
And use it as
var reportData = GetReportDataset(org).ToInterventionRiskReports().ToList();
... as I said, its not completely clear, which part you want to refactor into an extension method.

Contains on two values? [duplicate]

This question already has answers here:
Does .NET have a way to check if List a contains all items in List b?
(5 answers)
Closed 7 years ago.
I've got a List properties that must contain both pivot1 and pivot2.
How can I make Contains work with BOTH values?
List<string> properties = line.Split('|').ToList();
string pivot1 = "value1";
string pivot2 = "value2";
if(properties.Contains(pivot1) && properties.Contains(pivot2))
{
// do stuff.
}
Aside from writing an extension/helper method, you can use LINQ to shorten it a bit:
if (new[] { pivot1, pivot2 }.All(properties.Contains))
{
}
Although this is somewhat less readable I'd argue.
I personally like maintaining a Utility class to build up my own helpful framework to compliment .NET. I'd do something like:
public static bool ContainsAll<T>(this IEnumerable<T> list, params T[] items)
{
foreach(var item in items)
{
if (!list.Contains(item))
return false;
}
return true;
}
then you can use:
if(properties.ContainsAll(pivot1, pivot2))
{
}
You are not initializing properties or adding anything to it.
List<string> properties = new List<string>();
properties.Add("value1");
properties.Add("value2");
string pivot1 = "value1";
string pivot2 = "value2";
if(properties.Contains(pivot1) && properties.Contains(pivot2))
{
// do stuff.
}

Create object with results of Enumerable.Where and add them to a list

I want to query a set I already have and create new objects from the results. I also want those objects to be added to an existing LinkedList.
What I have right now is
var results = fulldata.Where(x => x.ImportantData == ImportanceLevel.HIGH);
Now results contain a set of data objects defined liked this :
public class DataObject{
public int x;
public int y;
public int DataType;
}
I'd like to write with the same syntax (as the Where() list comprehension method) an equivalent of the following code :
var prunedResults = new LinkedList<KeyValuePair<int, int>>();
foreach(var res in results){
if(res.DataType == DataTypeSpecial){
prunedResults.Add(new KeyValuePair<int, int>(res.x, res.y));
}
}
I'm pretty new to "modern" C# so if you could also define terms used here, it would help me to google further answers. What I mean is that this seems to be called LINQ and the Where() call is using a lambda expression, but I could be somewhat wrong.
var prunedResults = new LinkedList<KeyValuePair<int, int>>();
//do other stuff to prunedResults
prunedResults.AddRange(results.Where(x => x.DataType == DataTypeSpecial)
.Select(res=> new KeyValuePair<int, int>(res.x, res.y)));

update a List<Object> with LINQ [duplicate]

This question already has answers here:
Update all objects in a collection using LINQ
(18 answers)
Closed 7 years ago.
I am trying to add a SELECT ALL functionality to my grid with LINQ, but I get a compilation error.
List<Person_> PeopleUpdated = People.ToList().ForEach(a => a.SELECTED = true).ToList();
It says
Cannot implicitly convert type 'void' to
'System.Collections.Generic.List <
LogoSapHrIntegration.frmXmlUpload.Person_>'
what am I doing wrong?
The List<T>.ForEach has no return value (ie void), so you can't run ToList() against that. (see MSDN)
ForEach a specific action for each item in the list (just like doing a real for loop).
In your case a simple for loop to select all is most efficient.
foreach (var person in People)
person.Selected = true
List<T>.ForEach returns void (in your case, it changes your collection in place). ForEach takes an Action<T> and executes that on each item of your list.
See List(T).ForEach on MSDN
The ForEeach method (which is not LINQ) runs an action on each item in the list, it's not used to filter out items from a list so it doesn't return a result.
Just run the method on each item; there is no result to assign:
People.ToList().ForEach(a => a.SELECTED = true);
If you wanted a new list of items where the property was changed, you would need to clone the items to make them separate from the originals:
List<Person_> PeopleUpdated = People.ToList().Select(a => {
Person_ b = a.Clone();
b.SELECTED = true;
return b;
}).ToList();
(If the class doesn't support cloning, you would need to implement the Clone method (and preferably the IClonable interface).)
First of all, you can use a normal foreach loop:
foreach (var person in people)
{
person.Selected = true;
}
Which is the simplest and cleanest.
If you really want to jump to hoops and use LINQ, you can use ConvertAll:
var list = new List<Person> { new Person(), new Person() };
var convertedPeople = list.ConvertAll(person =>
{
person.Selected = true;
return person;
});

Categories