c# Trying to reverse a list - c#

I have the following code:
public class CategoryNavItem
{
public int ID { get; set; }
public string Name { get; set; }
public string Icon { get; set; }
public CategoryNavItem(int CatID, string CatName, string CatIcon)
{
ID = CatID;
Name = CatName;
Icon = CatIcon;
}
}
public static List<Lite.CategoryNavItem> getMenuNav(int CatID)
{
List<Lite.CategoryNavItem> NavItems = new List<Lite.CategoryNavItem>();
-- Snipped code --
return NavItems.Reverse();
}
But I get the following error:
Cannot implicitly convert type 'void' to 'System.Collections.Generic.List<Lite.CategoryNavItem>'
Any ideas why this might be?

Try:
NavItems.Reverse();
return NavItems;
List<T>.Reverse() is an in-place reverse; it doesn't return a new list.
This does contrast to LINQ, where Reverse() returns the reversed sequence, but when there is a suitable non-extension method it is always selected in preference to an extension method. Plus, in the LINQ case it would have to be:
return someSequence.Reverse().ToList();

One workaround would be Return NavItems.AsEnumerable().Reverse();

.Reverse() on a list reverses the items within the list, it does not return a new reversed list.

Reverse() does not returns reversed list itself, it modifies original list. So rewrite it as following:
return NavItems.Reverse();
TO
NavItems.Reverse();
return NavItems;

Reverse() does not return a List as expected of your function.
NavItems.Reverse();
return NavItems;

If you have a list like in your example:
List<Lite.CategoryNavItem> NavItems
You can use the generic Reverse<> extensions method to return a new list without modifiying the original one. Just use the extension method like this:
List<Lite.CategoryNavItem> reversed = NavItems.Reverse<Lite.CategoryNavItem>();
Notes: You need to specify the <> generic tags to explicit use the extension method.
Don't forget the
using System.Linq;

.Reverse reverses the "in-place"..., try
NavItems.Reverse();
return NavItems;

I had a situation where none of the suggested options suited me. So, if you:
don't want to use someList.Reverse() because it returns nothing (void)
don't want to use someList.Reverse() because it modifies source list
use someList.AsEnumerable().Reverse() and get the Ambiguous invocation error
You can try Enumerable.Reverse(someList) instead.
Don't forget the:
using System.Linq;

Related

Linq query List<List<class>> Where property of class C#

Could someone suggest a way for me to select one of the lists within a parent list where one of it's elements has a certain property value?
public class HierarchyLevel
{
public string Abbreviation;
public string Name;
public string Value;
public Type LevelType;
public List<HierarchyLevel> Children = new List<HierarchyLevel>();
}
public static List<List<HierarchyLevel>> ElementaryTypes = new List<List<HierarchyLevel>>();
I am actually trying to get the List that has the LevelType field of a specific type.
You wrote:
I am actually trying to get the List that has the LevelType field of a specific type.
What do you want if you've got several HierarchyLevels with this LevelType? And what do you want if there are no HierarchyLevels at all with this LevelType?
Let's assume that you want all HierarchyLevels with this LevelType. If later on you only want the first, or the one with a certain Abbreviation (or whatever), you could always use .FirstOrDefault, or .Where. and do a ToList in the end.
Implementing it as an extension function. See Extension Methods Demystified
public static IEnumerable<HierarchyLevel> GetHierarchyLevelsWithLevelType(
this IEnumerable<HierarchyLevel> hierarchyLevels,
LevelType desiredLevelType)
{
foreach (var hierarchyLevel in hierarchyLevels)
{
if (hierarchyLevel.LevelType == desiredLevelType)
{ // found one!
yield return hierarchyLevel;
}
// using recursion: check all the Children
IEnumerable<HierarchyLevel> childrenWithDesiredLevelType = hierarchyLevel.Children
.GetHierarchyLevelsWithLevelType(desiredLevelType);
foreach(var childWithDesiredLevelType in childrenWithDesiredLevelType)
{
yield return childWithDesiredLevelType;
}
}
}
Because of the recursion all Grandchildren and their Children etc will be returned
usage:
var allSpecialHierarchies = myHierarchies.GetHierarchyLevelsWithLevelType(LevelType.Special);
// get the first:
var firstSpecialHierarchy = allSpecialHierarchies.FirstOrDefault();
// get the first three named "Shakespeare:
var threeShakesPeares = allSpecialHierarchies
.Where(hierarchyLevel => hierarchyLevel.Name == "Shakespeare")
.Take(3)
For better usage you should provide a version that has a parameter IQualityComparer<LevelType>. Let the function above call that one.
And a nice challenge: to be fully LINQ compatible, create a version with a predicate that returns a type T and an equality comparer for this type T, so that you can have all HierarchyLevels with a certain Name, or Abbreviation.
You can Solve your with the help of recursion consider example below :- I have taken sample type of String you can use any of your Type
List<List<HierarchyLevel>> sample = new List<List<HierarchyLevel>>();
Type yourType = typeOf(string);
List<HierarchyLevel> filtered = sample.Where(x => ContainsElement(x, yourType));
public void bool ContainsElement(List<HierarchyLevel> list,Type yourType)
{
if(list.Any(x => x.LevelType == yourType) //check if current node has same level type
return true;
else if(list.Childern.Count > 0) //check if current node has children if yes then call ContainsElement again
return list.Children.Any(x => ContainsElement(x,yourType));
else
return false; //else return false in last
}
Thanks to user743414 for pointing out how simple this was :)
By using a dictionary instead, I could reference to the specific list. (This is also a faster option.)
Dictionary<Type,List<HierarchyLevel>> HierarchicalData;
I can now use it with a key of 'Type':
private void UpdateGeneralData(object Entity, Dictionary<Type,List<HierarchyLevel>> TypeData)
{
CBType.Items.Clear();
foreach (var item in TypeData[Entity.GetType()])
{
CBType.Items.Add(item);
}
}
Something like this (?):
List<HierarchyLevel> var = hLevel.Select(h => h.Children.Where(c => c.Param = "desired param")).ToList();

Filter and keep first object of a List of objects with properties that match

I apologize upfront, because I now realize that I have completely worded my example wrong. For those who have given responses, I truly appreciate it. Please let me re-attempt to explain with a more accurate details. Please edit your responses, and once again, I apologize for not being more exact in my previous posting.
Using an entity framework model class called Staging (which is a representation of my Staging table), I have the following List<Staging>.
List<Staging> data = (from t in database.Stagings select t).ToList();
//check for an empty List...react accordingly...
Here is a quick look at what Staging looks like:
public partial class Staging
{
public int ID { get; set; } //PK
public int RequestID { get; set; } //FK
...
public string Project { get; set; }
...
}
Let us suppose that the query returns 10 records into my data list. Let us also suppose that data[3], data[6], and data[7] each have the same value in data.Project, let's say "Foo". The data.Project value is not known until runtime.
Given this, how would I keep the first occurrence, data[3], and remove data[6] and data[7] from my List<Staging>?
Edit:
I have the following code that works, but is there another way?
HashSet<string> projectValuesFound = new HashSet<string>();
List<Staging> newData = new List<Staging>();
foreach (Staging entry in data)
{
if (!projectValuesFound.Contains(entry.Project))
{
projectValuesFound.Add(entry.Project);
newData.Add(entry);
}
}
You can do this via LINQ and a HashSet<T>:
var found = new HashSet<string>();
var distinctValues = theList.Where(mc => found.Add(mc.Var3));
// If you want to assign back into the List<T> again:
// theList = distinctValues.ToList();
This works because HashSet<T>.Add returns true if the value was not already in the set, and false if it already existed. As such, you'll only get the first "matching" value for Var3.
var uniques = (from theList select theList.Var3).Distinct();
That will give you distinct values for all entries.
You could use Linq:
var result = (from my in theList where my.Var3 == "Foo" select my).First();
If you also want to keep the other items, you can use Distinct() instead of First(). To use Dictinct(), either MyClass must implement IEquatable<T>, or you must provide an IEqualityComparer<T> as shown in the MSDN link.
The "canonical" way to do it would be to pass appropriately implemented comparer to Distinct:
class Var3Comparer : IEqualityComparer<MyClass> {
public int GetHashCode(MyClass obj) {
return (obj.Var3 ?? string.Empty).GetHashCode();
}
public bool Equals(MyClass x, MyClass y) {
return x.Var3 == y.Var3;
}
}
// ...
var distinct = list.Distinct(new Var3Comparer());
Just beware that while current implementation seems to keep the ordering of the "surviving" elements, the documentation says it "returns an unordered sequence" and is best treated that way.
There is also a Distinct overload that doesn't require a comparer - it just assumes the Default comparer, which in turn, will utilize the IEquatable<T> if implemented by MyClass.

linq casting to object

I have a linq query as follow:
public static ViewUserDisplayPreferences GetUserDisplayPreferences(int TheUserID)
{
using ( MyDataContext TheDC = new MyDataContext() )
{
var OutputUserDisplayPreferences = from user in TheDC.Users
where user.UserID == TheUserID
select new ViewUserDisplayPreferences
{
UserTimeFormat = user.UserTimeDisplay
};
return (ViewUserDisplayPreferences)(OutputUserDisplayPreferences);
}
}
For the moment, the object ViewUserDisplayPreferences is defined as follow (more variables will be added later):
public class ViewUserDisplayPreferences
{
public string UserTimeFormat { get; set; }
};
On the return statement at runtime, I get this error:
Unable to cast object of type
'System.Data.Linq.DataQuery`1[ObjectsUsers.ViewUserDisplayPreferences]'
to type
'ObjectsUsers.ViewUserDisplayPreferences'.]
What's wrong with the code? The intellisense is not showing any error on the line?
Thanks
OutputUserDisplayPreferences is an IEnumerable<T>. If you want an object, use either the First (if there can be more than one) or Single (if you know for sure only one object will be in the sequence) method on the sequence. If it is possible for the sequence to be empty, use the respective *OrDefault method.
Linq returns a collection. Try adding a .FirstOrDefault to the end.

Interfaces and casting lists

Why doesnt this work, and how to fix?
public interface ITheInterface
{
string a{get;set;}
string b{get;set;}
}
public class SomeObject: ITheInterface
{
string a{get;set;}
string b{get;set;}
...
}
public class SomeGroup
{
ITheInterface Result;
...
}
var results= from y in dc.Groups
where y.id==1
select new SomeGroup
{
Result= (from x in dc.Objects
select new SomeObject{... }
).SingleOrDefault(),
}
return results.ToList();
Could not convert from type System.Collections.Generic.List to Interface
I assume your problem is with the Results.ToList() call? It will fail, because ITheInterface does not support ToList(). You are calling SingleOrDefault() on the LINQ query, which is giving you a single item. It doesn't make sense to call ToList() on a single item.
If, instead, your code read like this:
IEnumerable<SomeObject> Results = from x in dc.Objects
select new SomeObject{... };
Then, Results.ToList() will give you a List<SomeObject>.
If what you are actually looking for is a List<ITheInterface> instead, you can do this:
Results.Cast<ITheInterface>().ToList()
Results is a single object; ToList() only works on Enumerables.
You need to either write return new List { Results }; (this uses a collection initializer) or get rid of the call to SingleOrDefault and declare Results as an IEnumerable<ITheInterface>.
If you only want one object, why are you returning a List?
In addition to the other answers, when you implement an interface, you must declare the member functions as public:
public class SomeObject: ITheInterface
{
public string a{get;set;}
public string b{get;set;}
...
}
You want to say
SomeGroup result = results.SingleOrDefault()
return result;
This is because the return type of your method is SomeGroup (I'm inferring)

LINQ: How to declare IEnumerable[AnonymousType]?

This is my function:
private IEnumerable<string> SeachItem(int[] ItemIds)
{
using (var reader = File.OpenText(Application.StartupPath + #"\temp\A_A.tmp"))
{
var myLine = from line in ReadLines(reader)
where line.Length > 1
let id = int.Parse(line.Split('\t')[1])
where ItemIds.Contains(id)
let m = Regex.Match(line, #"^\d+\t(\d+)\t.+?\t(item\\[^\t]+\.ddj)")
where m.Success == true
select new { Text = line, ItemId = id, Path = m.Groups[2].Value };
return myLine;
}
}
I get a compile error,because "myLine" is not a IEnumerable[string] and I don't know how to write IEnumerable[Anonymous]
"Cannot implicitly convert type 'System.Collections.Generic.IEnumerable[AnonymousType#1]' to 'System.Collections.Generic.IEnumerable[string]'"
You cannot declare IEnumerable<AnonymousType> because the type has no (known) name at build time. So if you want to use this type in a function declaration, make it a normal type. Or just modify your query to return a IENumerable<String> and stick with that type.
Or return IEnumerable<KeyValuePair<Int32, String>> using the following select statement.
select new KeyValuePair<Int32, String>(id, m.Groups[2].Value)
I am not necessarily recommending this...
It is a kind of subversion of the type system but you could do this:
1) change your method signature to return IEnumerable (the non generic one)
2) add a cast by example helper:
public static class Extensions{
public static IEnumerable<T> CastByExample<T>(
this IEnumerable sequence,
T example) where T: class
{
foreach (Object o in sequence)
yield return o as T;
}
}
3) then call the method something like this:
var example = new { Text = "", ItemId = 0, Path = "" };
foreach (var x in SeachItem(ids).CastByExample(example))
{
// now you can access the properties of x
Console.WriteLine("{0},{1},{2}", x.Text, x.ItemId, x.Path);
}
And you are done.
The key to this is the fact that if you create an anonymous type with the same order, types and property names in two places the types will be reused. Knowing this you can use generics to avoid reflection.
Hope this helps
Alex
The method signature on SearchItem indicates that the method returns an IEnumerable<string> but the anonymous type declared in your LINQ query is not of type string. If you want to keep the same method signature, you have to change your query to only select strings. e.g.
return myLine.Select(a => a.Text);
If you insist on returning the data selected by your query, you can return an IEnumerable<object> if you replace your return statement with
return myLine.Cast<object>();
Then you can consume the objects using reflection.
But really, if your going to be consuming an anonymous type outside the method that it is declared in, you should define a class an have the method return an IEnumerable of that class. Anonymous types are convenience but they are subject to abuse.
Your function is trying to return IEnumerable<string>, when the LINQ statement you are executing is actually returning an IEnumerable<T> where T is a compile-time generated type. Anonymous types are not always anonymous, as they take on a specific, concrete type after the code is compiled.
Anonymous types, however, since they are ephemeral until compiled, can only be used within the scope they are created in. To support your needs in the example you provided, I would say the simplest solution is to create a simple entity that stores the results of your query:
public class SearchItemResult
{
public string Text { get; set; }
public int ItemId { get; set; }
public string Path { get; set; }
}
public IEnumerable<SearchItemResult> SearchItem(int[] itemIds)
{
// ...
IEnumerable<SearchItemResult> results = from ... select new SearchItemResult { ... }
}
However, if your ultimate goal is not to retrieve some kind of object, and you are only interested in, say, the Path...then you can still generate an IEnumerable<string>:
IEnumerable<string> lines = from ... select m.Groups[2].Value;
I hope that helps clarify your understanding of LINQ, enumerables, and anonymous types. :)
Return a ValueTuple instead of an anonymous class. Ex (using "named tuples")-
(Text: line, ItemId: id, Path: m.Groups[2].Value)
https://learn.microsoft.com/en-us/dotnet/csharp/tuples
Instead of-
new { Text = line, ItemId = id, Path = m.Groups[2].Value }
The ValueTuple is part of C# version 7 and was originally implemented as a separate NuGet package (System.ValueTuple). Starting with .NET 4.7 it is a built-in type. For .NET Core, versions prior to 2.0 required the NuGet package but it is built-in with version 2.0.
The question was asked a long time ago, I hope it helps someone...
"You cannot declare IEnumerable", instead, must convert it to a "custom" IEnumerable:
public class MyString
{
public string String { get; set; } = string.Empty;
}
public IEnumerable<MyString> GetMyStrings(List<string> Strings)
{
var AnonString = from S in Strings group S by S into Grouped select new { String = Grouped.Key };
IEnumerable<MyString> Result = AnonString.Select(x => new MyString() { String = x.String }).ToArray();
return Result;
}
Regards.
this link could be useful for others who end up here
https://idreesdotnet.blogspot.com/2019/08/c-how-to-create-list-of-anonymous-type.html
the first solution (of 6) is delightlfully simple
1: First create the object(s) of anonymous type and then pass it to an array and call ToList() method.
var o1 = new { Id = 1, Name = "Foo" };
var o2 = new { Id = 2, Name = "Bar" };
var list = new[] { o1, o2 }.ToList();

Categories

Resources