Remove list item where it matches text - c#

Below I check to see if a text value is in LstNewItems and NOT in ListOfItemsToControl. This works fine. Within the if statement i want to remove the row from LstNewItems that matches the text value? lstNewItems is a list.
string name = rows[i].Cells[0].Value.ToString();
if (MyGlobals.lstNewItems.Any(x => x.sItemName == name) && !MyGlobals.ListOfItemsToControl.Any(y => y.sItemName == name))
{
//Remove the row from LstNewItems that matches the text value
}

It's not clear what the collection actually is.
If it's a generic List<> you can do:
MyGlobals.lstNewItems.RemoveAt(i);
Tell me if it works otherwise give us the exact type of the collection.
Remember you can't modify a collection inside a loop that uses it as an enumeration. Like this:
foreach (var x in MyGlobals.lstNewItems)
{
MyGlobals.lstNewItems.Remove(x); // will throw an InvalidOperationException
}

if (MyGlobals.lstNewItems.Any(x => x.sItemName == rows[i].Cells[0].Value.ToString() && !MyGlobals.ListOfItemsToControl.Any(y => y.sItemName == rows[i].Cells[0].Value.ToString())))
{
MyGlobals.lstNewItems.RemoveAll(item => item.sItemName == rows[i].Cells[0].Value.ToString());
}

Related

Linq value, use Where to Remove items

I am trying to remove items from an IQueryable list but the result is only pulling in those items:
public IQueryable<Biz.Data.AllItems> items_GetData()
{
var submissions = Biz.Data.AllItems.LoadNotDeleted().Where(x =>
// these items need to match to remove the item
x.itemOne != null &&
x.itemTwo != null &&
x.itemThree != null));
var filter = new Biz.Data.AllItemsFilter();
return submissions = Biz.Data.Registration.Load(filter).OrderBy(x => x.LastName).ThenBy(x => x.FirstName);
}
Currently, it's only pulling in items that match those instead of removing. I can't use RemoveAll because it's not a List and I don't want to reformat this because it passes through a filter process after this code. Is there another way to remove items that match these results first before it passes through a filter?
As discussed in comments, simply negate the condition in your predicate.
So if this is your original statement:
var itemsThatMatch = list.Where(x => /* some condition */);
This will give you the opposite:
var itemsThatDoNotMatch = list.Where(x => !(/* some condition */));

Remove List elements that are same

I currently have two lists of Directory Info. Candidatelist & VersionList. VersionList being a sublist of candidate list. I'm trying to remove all the elements from candidate list that appear in version list. So if canadidate list has 177 elements and version list has 77 then we have 100 elements left in candidate list. To be more explicit of whats inside the list. Each element correspons to a directory folder name who has a name and a parent folder name. It is possible that the directory name has duplicates but diffeerent parents. I tried doing this but I'm not necesarily getting the correct result Take a look:
candidateList.RemoveAll(x => versionslist.Any(y => y.Name == x.Name) && versionslist.Any(y => y.Parent.Name == x.Parent.Name));
return candidateList;
Your current query is not constraining business requirements to a single version list item. It's making the two queries separately. It's saying:
Are there any versionList items where the Name matches the current candidateList item name
If yes:
Are there any versionList items where the Parent.Name matches the current candidateList item Parent.Name
If yes, remove the item from the candidate list. Instead, you should be querying for a versionList item that meets both requirements pieces at the same time.
candidateList.RemoveAll(x => versionslist.Any(y => y.Name == x.Name && y.Parent.Name == x.Parent.Name));
return candidateList;
This is now saying:
Are there any versionList items where the Name and Parent.Name matches the current candidateList item Name and Parent.Name, respectively.
You can use IEnumerable.Except() method with custom IEqualityComparer:
var differences = candidateList.Except(versionList, new DirectoryInfoComparer());
The EqualityComparer could look like this:
public class DirectoryInfoComparer : IEqualityComparer<DirectoryInfo>
{
bool IEqualityComparer<DirectoryInfo>.Equals(DirectoryInfo x, DirectoryInfo y)
{
return (x.Name == y.Name) && (x.Parent.Name == y.Parent.Name);
}
int IEqualityComparer<DirectoryInfo>.GetHashCode(DirectoryInfo obj)
{
if (Object.ReferenceEquals(obj, null))
return 0;
return obj.GetHashCode();
}
}
As you mentioned, you want to remove all the elements from version list that appear in canadidate list. I think then your syntax should be like:
VersionList.RemoveAll(x => candidateList.Any(y => y.Name == x.Name && y.Parent.Name == x.Parent.Name);
return VersionList;
if it is vice versa, then use
candidateList.RemoveAll(x => VersionList.Any(y => y.Name == x.Name && y.Parent.Name == x.Parent.Name);
return candidateList;

Remove list items where property = myValue

I've got a problem. I have a list of objects (vehicle).
List<Vehicle> vehicleList = Vehicle.GetVehiclesFromDatabase();
And now I want something like this:
vehicleList.Remove(where vehicleList.Brand == "Volkswagen");
I hope I could explain what my problem is.
Many thanks in advance!
You can use List<T>.RemoveAll:
int recordsRemoved = vehicleList.RemoveAll(v => v.Brand == "Volkswagen");
The method takes a Predicate<T> (= Func<T,bool>), which will remove all items for which the predicate returns true.
For you this is equal to the following method:
bool Filter(Vehicle vehicle)
{
return vehicle.Brand == "Volkswagen";
}
You can use linq to do this, like so
vehicleList = vehicleList.Where(v => v.Brand != "Volkswagen").ToList();
You can also do this with a RemoveAll
vehicleList.RemoveAll(v => v.Brand == "Volkswagen");
You can do like this
var itemToRemove = vehicleList.Single(r => r.Brand == "Volkswagen");
resultList.Remove(itemToRemove);
When you are not sure the item really exists you can use SingleOrDefault. SingleOrDefault will return null if there is no item (Single will throw an exception when it can't find the item). Both will throw when there is a duplicate value (two items with the same id).
var itemToRemove = vehicleList.SingleOrDefault(r => r.Brand == "Volkswagen");
if (itemToRemove != null)
resultList.Remove(itemToRemove);

How to get next item from list based on some condition in C#?

I have a List which contains set of time frames (DataTime format). It has StartDateTime & EndDateTime. I am trying to get a next item of the list based on a condition. How can I do that?
For Example,
foreach (var currentTimeSlot in prepBlock.EligiblePickupTimes.BlockList)
{
if (potentialStartTime > currentTimeSlot.EndDateTime)
{
//Skip current time slot and grab next one and so on.
}
}
You can use FirstOrDefault in order to get the first item matching your predicate:
prepBlock.EligiblePickupTimes.BlockList
.FirstOrDefault(x => potentialStartTime <= x.EndDateTime);
You can get the entire Enumerable<T> of items from the first matches this condition to the end using SkipWhile:
prepBlock.EligiblePickupTimes.BlockList
.SkipWhile(x => potentialStartTime > x.EndDateTime);
The first condition is equivalent to the following code:
prepBlock.EligiblePickupTimes.BlockList
.SkipWhile(x => potentialStartTime > x.EndDateTime)
.FirstOrDefault();
From what is see you try to do in the image you can do the following:
returnValue.IsEstimateSuccessful &= !prepBlock.EligiblePickupTimes.BlockList
.SkipWhile(x => potentialStartTime > x.EndDateTime)
.Any();
Unless I'm missing something, I believe you can accomplish this with the .FirstOrDefault method as mentioned in comments.
using System.Linq;
...
var nextAvailableItem =
prepBlock.EligiblePickupTimes.BlockList
// reversing your condition above to find value I want
// instead of specifying values I don't want
.FirstOrDefault(x => potentialStartTime <= x.EndDateTime)
;
// did we find a value to match our condition?
var wasFound = nextAvailableItem != default(DateTime);
If you are just trying to loop through all the timeslots where potentialStartTime is greater than it's EndDateTime, then:
foreach (var currentTimeSlot in
prepBlock.EligiblePickupTimes.BlockList.Where(x=>potentialStartTime > x.EndDateTime))
{
}
based on your image, I think this is what you are looking for however:
returnValue.IsEstimateSuccessful=!prepBlock
.EligiblePickupTimes
.BlockList
.Any(x=>potentialStartTime > x.EndDateTime);
if returnValue.IsEstimateSuccessful is set prior to that (like if you default it to true, and many checks might turn it false):
returnValue.IsEstimateSuccessful&=!prepBlock
.EligiblePickupTimes
.BlockList
.Any(x=>potentialStartTime > x.EndDateTime);

Select 1 object from list with LINQ based on 2 vars

I've been trying to solve this by reading what was on StackOverflow and the information was quiet helpful but i can't seem to implement the things i found.
I have a data List and i want to check if an entry exists in the data set that match 2 variables i provide.
public void SaveWaveDataFor( List<WaveData> newData )
{
foreach(WaveData wave in newData)
{
//WaveData item = data.FirstOrDefault( o => o.id == wave.id );
var item = data.Select( o => new{ wave.id, wave.waveNumber } );
Debug.Log( item.id );
}
}
If you want to get all of the wave objects that match two criteria, you can use a Where() clause:
// items will be an IEnumerable<WaveData> containing the matching objects
// where id == matchId and waveNumber == matchNumber
var items = data.Where(o => o.id == matchId && o.waveNumber == matchNumber);
The Select() clause is typically used to transform the matching elements into objects of another type.
The commented out line is better for this actually.
FirstOrDefault will return either the first matching item or null if no items match.
On the other hand, you could use Any() if you just want to know if an item exists.
Any(x=>x.Id == matchId) will return true only if the list contains an item with a matching Id, false otherwise.
You would do it like this:
public void SaveWaveDataFor( List<WaveData> newData )
{
int waveIdToMatch = 1;
int waveNumberToMatch = 2;
foreach(WaveData wave in newData)
{
WaveData item = data.FirstOrDefault( o => o.id == waveIdToMatch && o.waveNumber == waveNumberToMatch );
//if a match exists, item will not be a WaveData object, otherwise it will be null
Debug.Log( item.id );
}
}
If you just want to check whether entry exists or not then you can use Any Operator from Linq.
bool recordsExists = data.Any(o => o.id == matchId && o.waveNumber == matchNumber);

Categories