c# remove item from list without knowing index number - c#

I have a list with collection of my object:
List<MyObj> list = new List<MyObj>();
My function received MyObj as a parameter and i want to remove this object from the list like suggest here: c# remove item from list
private void remove(MyObj obj)
{
var itemToRemove = list.Where(x => x.fileName == obj.fileName);
if (itemToRemove != null)
list.Remove(itemToRemove);
}
Compiler error received:
cannot convert from 'System.Collections.Generic.IEnumerable' to 'namespace.MyObj'

Where() returns an IEnumerable<>
Try this:
private void remove(MyObj obj)
{
var itemToRemove = list.Where(x => x.fileName == obj.fileName);
if (itemToRemove.Any())
list.Remove(itemToRemove.First());
}
Better yet, as you're using List<>:
list.RemoveAll(x => x.fileName == obj.fileName);
Edit
Other solutions, that are all equally viable from the comments below. Pick your poison, though selfishly (and perhaps obviously) I prefer the readability and simplicity of the RemoveAll method:
Knittl:
list = list.Where(x => x.filename != obj.filename).ToList();
Jeroen van Langen:
var itemToRemove = list.Where(x => x.fileName == obj.fileName).FirstOfDefault();
if (itemToRemove != null)
list.Remove(itemToRemove);

You were mixed up between Where and FirstOrDefault:
private void remove(MyObj obj)
{
var itemToRemove = list.FirstOrDefault(x => x.fileName == obj.fileName);
if (itemToRemove != null)
list.Remove(itemToRemove);
}

There is no need for you to implement this method, the remove method of List already performs this operation as expected.
http://msdn.microsoft.com/en-us/library/cd666k3e.aspx
public bool Remove(
T item
)

You should use RemoveAll method exposed by list to remove all the matching elements -
private void remove(MyObj obj)
{
var itemToRemove = list.RemoveAll(x => x.fileName == obj.fileName);
}

Related

Why EF code is not selecting a single column?

I have used this to pick just a single column from the collection but it doesn't and throws casting error.
ClientsDAL ClientsDAL = new DAL.ClientsDAL();
var clientsCollection= ClientsDAL.GetClientsCollection();
var projectNum = clientsCollection.Where(p => p.ID == edit.Clients_ID).Select(p => p.ProjectNo).ToString();
Method:
public IEnumerable<Clients> GetClientsCollection(string name = "")
{
IEnumerable<Clients> ClientsCollection;
var query = uow.ClientsRepository.GetQueryable().AsQueryable();
if (!string.IsNullOrEmpty(name))
{
query = query.Where(x => x.Name.Contains(name));
}
ClientsCollection = (IEnumerable<Clients>)query;
return ClientsCollection;
}
As DevilSuichiro said in comments you should not cast to IEnumerable<T> just call .AsEnumerable() it will keep laziness.
But in your case it looks like you do not need that at all because First or FirstOrDefault work with IQueryable too.
To get a single field use this code
clientsCollection
.Where(p => p.ID == edit.Clients_ID)
.Select(p => p.ProjectNo)
.First() // if you sure that at least one item exists
Or (more safe)
var projectNum = clientsCollection
.Where(p => p.ID == edit.Clients_ID)
.Select(p => (int?)p.ProjectNo)
.FirstOrDefault();
if (projectNum != null)
{
// you find that number
}
else
{
// there is no item with such edit.Clients_ID
}
Or even simpler with null propagation
var projectNum = clientsCollection
.FirstOrDefault(p => p.ID == edit.Clients_ID)?.ProjectNo;

Lambda expression and class method

I have a problem like this.
List<Absent> absent = new List<Absent>();
Console.WriteLine("--------------------------");
Console.Write("Please enter a full name> ");
string temp_str = Console.ReadLine();
absent.Where(x => x.Name == temp_str).Run(x = x.WriteConsoleTable());
How can I run a method after doing a filtering?
Absent is a Class which has a Name variable and WriteConsoleTable method.
Seems like you're looking for the ForEach extension method but you'll first need to call ToList on the IEnumerable sequence returned from the Where clause.
absent.Where(x => x.Name == temp_str)
.ToList()
.ForEach(x => x.WriteConsoleTable());
or you can iterate over the collection using the foreach construct.
i.e.
foreach (var item in absent.Where(x => x.Name == temp_str))
item.WriteConsoleTable();
You can try below options.
var absences = absent.Where(x => x.Name == temp_str);
foreach(var abs in absences)
{
abs.WriteConsoleTable();
}
or if you are sure you only need first match
var absence = absent.FirstOrDefault(x => x.Name == temp_str);
if(absence != null)
{
absence.WriteConsoleTable();
}

Get Method is null off IQueryable (Entity Framework)

I'm trying to pass lambda expressions and a type to my DAL. I have this statement:
(entities).GetType().GetMethod("Where")
"entities" is the Table of entities on the DataContext.
When I run the statement I get a null even though Linq.Table inherits IQueryable.
Anyone have an idea?
Here is the entire method:
public object GetResultSet(Dictionary<Type, Func<object, bool>> values)
{
using (ICSDataContext db = DataContextFactory.CreateDataContext<ICSDataContext>(DataContexts.ICS))
{
foreach (var entry in values)
{
var property = db.GetType().GetProperty(entry.Key.Name + "s");
IQueryable entities = (IQueryable)property.GetValue(db, null);
var whereMethod = (entities).GetType().GetMethod("Where")
.MakeGenericMethod(Type.GetType(entry.Key.AssemblyQualifiedName));
return whereMethod.Invoke(entities, new object[] { entry.Value });
}
}
return null;
}
Thanks
As an alternative you could do something like
db.Set<Type>()
which will return you the DBSet of the appropriate type, with Where accessible without reflection. Also you may want to use Expression> rather than Func, expressions work on queryables where as funcs work on enumerables. If you pass a func into a Where clause it pulls the entire dbset down and processes it in memory.
Typed expressions are also a little easier to work with (intellesence, type checking).
Expression<Func<User,bool>> filter = c=>c.FirstName == "Bob";
As another alternative you can look into System.Linq.Dynamic, ScottGu has a write up on it here. The article and the code are old, but it works with EF 6. It allows things like
.Where("CategoryId=2 and UnitPrice>3")
From answer by LukeH under here:
var where1 = typeof(Queryable).GetMethods()
.Where(x => x.Name == "Where")
.Select(x => new { M = x, P = x.GetParameters() })
.Where(x => x.P.Length == 2
&& x.P[0].ParameterType.IsGenericType
&& x.P[0].ParameterType.GetGenericTypeDefinition() == typeof(IQueryable<>)
&& x.P[1].ParameterType.IsGenericType
&& x.P[1].ParameterType.GetGenericTypeDefinition() == typeof(Expression<>))
.Select(x => new { x.M, A = x.P[1].ParameterType.GetGenericArguments() })
.Where(x => x.A[0].IsGenericType
&& x.A[0].GetGenericTypeDefinition() == typeof(Func<,>))
.Select(x => new { x.M, A = x.A[0].GetGenericArguments() })
.Where(x => x.A[0].IsGenericParameter
&& x.A[1] == typeof(bool))
.Select(x => x.M)
.SingleOrDefault();
Then this:
var gmi = where1.MakeGenericMethod(typeof(T));

List<T>.ForEach() set property, return IEnumerable?

The LINQ extension List.ForEach() doesn't return anything (void), but I would like to assign a property value to all objects in a list and then return some of them as IEnumerable.
e.g.
return myCollection
.ForEach(x => x.ToBeDetermined = determine(x))
.Where(x => x.ToBeTermined == true);
return myCollection
.Select(x => {
x.ToBeDetermined = determine(x);
return x;
})
.Where(x => x.ToBeTermined == true);
Since you are setting a Boolean property and then filtering on it you can use this syntax:
return myCollection.Where(x => x.ToBeTermined = determine(x));
Note that you should at least write an explicit comment in the code because most people will see this as a typo and will be willing to "fix".
As an extension method, also making it more readable than other solutions (and also reusable):
public static IEnumerable<T> ForEachEx<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (T item in source)
{
action(item);
}
return source;
}
Which makes the usage exactly as you had it in your original question:
return myCollection.ForEachEx(x => x.ToBeDetermined = determine(x))
.Where(x => x.ToBeTermined == true);
The differences from the original ForEach are:
Returns IEnumerable<T> instead of void.
Works for every IEnumerable<T> and not just List<T>.
Do it in two steps:
myCollection.ForEach(x => x.ToBeDetermined = determine(x));
return myCollection.Where(x => x.ToBeTermined == true);
return myCollection.Where(determine).Select(x => { x.ToBeDetermined = true; return x; });

Equivalent to search within IEnumerable with LINQ

Is there a shorter, elegant way to write the following using LINQ?
var actorName = string.Empty;
foreach (var myProperty in myProperties)
{
if (myProperty .PropertyName == "ActorName")
{
actorName = myProperty .PropertyValue;
break;
}
}
var actorName = myProperties
.FirstOrDefault(x => x.PropertyName == "ActorName")
.PropertyValue;
This would give a NPE if nothing could be found though (FirstOrDefault returns null as default).
To combat this, use two statements instead:
var actor = myProperties
.FirstOrDefault(x => x.PropertyName == "ActorName");
var actorName = actor == null ? string.Empty : actor.PropertyValue;
In addition to Jeroen's answer.. its safer to check for null first.. since FirstOrDefault returns null when there is nothing that matches:
var actor = myProperties
.FirstOrDefault(x => x.PropertyName == "ActorName");
if (actor != null)
actorName = actor.PropertyValue;
Pure LINQ version, for the hell of it, though I'd prefer Simon's answer.
var actorName = myProperties
.Where(x => x.PropertyName == "ActorName")
.Select(x => x.PropertyValue)
.Concat(new[]{ string.Empty })
.First();

Categories

Resources