I'm trying to use a lambda expression to remove a certain object from a list, based on a value within that object. Here is my lambda:
ChartAttributes.ToList().RemoveAll(a => a.AttributeValue.Contains("PILOT"));
Here is the ChartAttributes list
IList<IChartAttribute> ChartAttributes
Here is the object ChartAttribute contained within the above list
public virtual string AttributeKey { get; set; }
public virtual string AttributeValue { get; set; }
public virtual int ChartAttributeId { get; set; }
public virtual int ChartSpecificationId { get; set; }
There is a chart attribute with its AttributeKey set to "PILOT". But this never gets removed. What am I doing wrong?
Thanks
Your code is taking an IEnumerable, copying all of its elements into a list and then removing items from that copy. The source IEnumerable is not modified.
Try this:
var list = ChartAttributes.ToList();
list.RemoveAll(a => a.AttributeValue.Contains("PILOT"));
ChartAttributes = list;
EDIT
Actually a better way, without needing to call ToList:
ChartAttributes = ChartAttributes.Where(a => !a.AttributeValue.Contains("PILOT"));
Your call to .ToList() makes a new list, and you end up removing the item from that list.
Whatever ChartAttributes is, you're not touching the contents of that.
Basically you're doing this:
var newList = ChartAttributes.ToList();
newList.RemoveAll(...);
If you were to inspect the contents of newList at this point you'd notice that your object(s) had been removed, but ChartAttributes, whatever type that is, still has those objects present.
You will have to remove the objects directly from ChartAttributes, but since you didn't say which type that is, I can't give you an example of how to do that.
If you need to remove items and save to database, you can try this sample code:
foreach (var x in db.myEntities.Where(a => a.AttributeValue.Contains("PILOT")))
db.myEntities.Remove(x);
db.SaveChanges();
It doesn't use RemoveAll, but it's another option to save the contents.
I had a similar problem and did a cast instead (as my setter for the property was internal):
((List<IChartAttribute>)ChartAttributes).RemoveAll(a => a.AttributeValue.Contains("PILOT"));
Related
I have an object of type scenario that contains a list of objects type SN. There is another object of type scenarioSchema that also contains a list of objects type SNSchema.
I want to copy items (Doubles and Integers) from type SNSchema into type SN of object scenario.
scenario.V = new List<SN>();
scenario.V.Add(scenarioSchema.V.Select(x => x.Distro);
public class SN
{
public double Version { get; set; }
public int Distro { get; set; }
}
I know this behavior can be achieved through LINQ, basically what I want to do is to go through the whole list of items SNSchema and pass those to the list of object scenario.
I know this might be too simple, but I can't wrap my head around this.
Thanks,
I think you need AddRange()
scenario.V.AddRange(scenarioSchema.V.Select(x => new SN() { Distro = x.Distro}));
I have a List in a class that I have as a property:
public List<string> MyList { get; set; }
Data will be added to this list and eventually the data will be read. When the data is read, it will be read like:
foreach(string str in my_obj.MyList)
{
// do something
}
I could, of course, do:
foreach(string str in my_obj.MyList.Sort())
{
// do something
}
but since this is a class library I do not want the use to have to do anything. I also do not want the user to have to call a Sort() method within the class. What I would ideally have is the list being sorted every time an item is added or when it is read.
You can change your property like this, use a backing field and sort it in the getter method before you return the list to the caller:
private List<string> _myList;
public List<string> MyList
{
get { _myList.Sort(); return _myList; }
set { _myList = value; }
}
Ofcourse this will perform sorting when you attempt to add new item to your list like myobj.MyList.Add("foo"); to avoid this you can add another method e.g. AddToMyList and use _myList.Add instead.And also change the property type IEnumerable<string> to prevent the user from adding new items directly.
Handle adds via an add method in your class. Doesn't protect against direct access of the list but you can insert the item into the correct index of your list based upon your sort requirements.
This approach saves you resorting your list as a single hit.
Just another idea to consider.
You can implement such collection with ObservableCollection Class
Refer URL : http://msdn.microsoft.com/en-us/library/ms668604%28v=vs.110%29.aspx
Assuming there are no duplicates in you list you should use SortedSet It's a set, so it can't contain the same object twice (but how would you sort objects which are the same?), but otherwise it does exactly what you need.
You could also consider implementing IEnumerable in the class which contains the list, that would allow you to simple do foreach(string str in my_obj) You can then make the list private and sort it once after all objects are added. Right now each user which gets the list can also change it, remove items etc. Which may not be what you want.
The implementation can be as simple as this:
public class MyClass : IEnumerable<string>
{
private List<string> myList = new List<string>();
public MyClass()
{
// Fill myList...
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return myList.GetEnumerator();
}
public IEnumerator<string> GetEnumerator()
{
return myList.GetEnumerator();
}
}
You can use System.Linq namespace, after you add using System.Linq then you should be able to do following
List<string> list = new List<string>();
list = list.OrderByDescending(i => i).ToList();
OR if you want to sort ascending order
list = list.OrderBy(i => i).ToList();
If you call those methods after adding item. Your list will be sorted.
Why not to go with SortedList ??
I guess thats exactly what you are looking for. You can just ignore the value of "short" in SortedList or just provide some default value. Or may be you can find some means to utilize field too.
Here is my situation. I have 2 list of the same type. Imagine the names like these. FullList and ElementsRemoved. So in order to avoid the database roundtrip, anytime I delete an element from the fulllist I added to the list of ElementsRemoved in case of regret's user so he can revert the deletion.
I was thinking to loop inside my ElementsRemoved to insert them again into the FullList from where initially were removed.
There is any way to do this as simple with List Methods.
Something like
FullList.Insert, Add, ..... (x =>
in order to reduce line code and optimized?
Instead of deleting the item from your database consider using a flag in the table.
For example consider this entities table (written in TSQL):
CREATE TABLE Entity
(
Id INT IDENTITY PRIMARY KEY
,Name NVARCHAR(20) NOT NULL
,IsDelete BIT NOT NULL DEFAULT 0
);
This way you can set the IsDelete bit when the user deletes the entity which will prevent the data from being lost. The data can be pruned on a job in the off hours.
The would lead to only needing one list instead of keeping track of two lists.
public class Entity
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsDelete { get; set; }
}
public static void UndoDelete(IEnumerable<Entity> fullList, int[] removedIds)
{
foreach(var entity in fullList.Where(e => removedIds.Contains(e.Id)))
{
entity.IsDelete = false;
}
}
In case you cannot modify your application.
You can simply add the entities back in.
See List(T).AddRange
var entitiesToAdd = new[] { 2, 3, 4 };
var entitiesToInsert = ElementsRemoved.Where(e => entitiesToAdd.Contains(e.Id));
FullList.AddRange(entitiesToInsert);
In your front end make a class that holds a bool and your object:
public class DelPair<T>{
public bool IsDeleted{get;set;}
public T Item{get;set;}
}
Now instead of using a list of objects use a list of DelPair<YourClass> and set IsDeleted=true when deleting.
This pattern will also allow you to track other things, such as IsModified if it comes to that.
Based on OP comment that he's using an ENTITY class and needs it to function as such:
One option is to make your DelPair class inherit ENTITY. Another may be to put implicit casting operator:
...
// not exactly sure about the signature, trial/error should do :)
public static implicit operator T(DelPair<T> pair)
{
return pair.Item;
}
Suppose you have an element having a field id which uniquely identifies it.
class Element{public int id;}
In that case you can do this
FullList.Add(ElementsRemoved.FirstOrDefault(e=>e.id==id));
In case you want to add all elements use AddRange
FullList.AddRange(ElementsRemoved);
You can use the AddRange method
FullList.AddRange(ElementsRemoved);
But consider doing this
public class YourClass
{
public string AnyValue{get;set;}
public bool IsDeleted{get;set;}
}
And you have list like this List < YourClass> FullList. Now whenever user removes any item you just set the
IsDeleted = true
of the item that is removed. This will help you in keeping just one list and adding removing from the list
I have the following code:
public class Navigation
{
public Navigation()
{
SubNavigation = new List<Navigation>();
}
public int Order { get; set; }
public string Text { get; set; }
public string RouteName { get; set; }
public IList<Navigation> SubNavigation { get; set; }
}
I then have:
IList<Navigation> list = new List<Navigation>();
I populate the list with some data. Not all items have a sub navigation. Currently the navigation only goes one level deep.
Now I would like to sort both the navigation and the sub-navigation for each item by order. I have tried all kinds of approaches but no matter what I tried I could not get the sub-navigation to sort without re-creating the object. The below code works:
IList<Navigation> result = list.OrderBy(l => l.Order)
.Select(n => new Navigation
{
Order = n.Order,
Text = n.Text,
RouteName = n.RouteName,
SubNavigation = n.SubNavigation.OrderBy(s => s.Order).ToList()
}).ToList();
I am not in love with this approach and my question is if there is any cleaner/better way of doing this using LINQ and the method syntax?
You could add a new property on your object:
public IList<Navigation> OrderedSubNavigation
{
get
{
return SubNavigation.OrderBy(s => s.Order).ToList();
}
}
Then when you want the ordered one you just use that.
I have tried all kinds of approaches but no matter what I tried I could not get the sub-navigation to sort without re-creating the object.
Well no, you wouldn't be able to cleanly - because getting the subnavigation to be in a particular order requires modifying the existing object, and LINQ's not built for that. LINQ's built for queries, which shouldn't mutate the data they work on.
One option would be to only sort the subnavigation when you need to - live with the fact that it's unordered within a Navigation, and then when you actually need the subnavigation items (e.g. for display) you can order at that point. Aside from anything else, this will make it more efficient if you end up not displaying the subnavigation items.
What I have is basically:
public class Object{
public bool IsObjectValid { set; get; }
}
public class MyThing{
public List<Object> Objects { set; get; }
}
What I want to do:
public class ObjectsFiltered{
public List<Object> ValidObjects{
get{
var list = LFs.Sort<_LF> where (IsObjectValid == true);
return list;
}
}
}
I know there has to be a way to sort out the List, filtering out the bool true/false. I just can't seem to wrap my head around Linq fully. I just can't seem to find a tutorial that screams "AH HA!" about Linq Lambda to me :/
I'd rather just return a subset, only only keep one "object" alive... instead of my current setup of multiple sets of lists. KISS.
Ultimately I will use the bool-toggles to feed TreeViews on my WPF form(s).
Clarification: I think the goal is to have a one list (List Objects) and a couple properties that show a filtered version of Objects. Instead of having Objects, ObjecstValid, ObjectsInvalid, ObjectsSomeOtherRuleSet... each a different List...
I'd like to have One List to rule them all... and have properties that return a variation on the list, as desired.
You can use LINQ:
public IEnumerable<Object> ValidObjects{
get{
return LFs.Where(item => item.IsObjectValid)
.OrderBy(item => item.SomeProperty);
}
}
Unless you need a List<T>, it's better to return an IEnumerable<T>, so that you won't store it all in-memory.
The lambda expression item => item.SomeProperty is an inline function that takes a parameter called item and returns item.SomeProperty. (The parameter and return types are inferred by the compiler)
To filter your objects, you can return simply:
return LFs.Where(x => x.IsObjectValid).ToList();
Note, however, that if you intend to draw on that function frequently, you may see some performance boost by maintaining a pre-filtered list internally.
LFs.Where(x => x.IsObjectValid).ToList().Sort()
To sort useing default compared. Otherwise
LFs.Where(x => x.IsObjectValid).OrderBy(x => x.PropertyToSortBy).ToList();