I have a list of class objects UserData. I get an object from this list through where method
UserData.Where(s => s.ID == IDKey).ToList(); //ID is unique
I would like to make some changes in the object and insert at the same location in the list. However, I donot have the index of this object.
Any idea how to do it ?
Thanks
You can get the index using the method
UserData.FindIndex(s => s.ID == IDKey)
It will return an int.
When your getting the item from a LIST its an reference type, if your updating anything to it then it will automatically change the values in LIST. Please check your self after updating...........
Item whichever your getting from
UserData.Where(s => s.ID == IDKey).ToList();
is an reference type.
As long as UserData is reference type, the list only holds references to instances of that object. So you can change its properties without the need of remove/insert (and obviously do not need index of that object).
I also suggest you want to use Single method (instead of ToList()) as long as the id is unique.
Example
public void ChangeUserName(List<UserData> users, int userId, string newName)
{
var user = users.Single(x=> x.UserId == userId);
user.Name = newName; // here you are changing the Name value of UserData objects, which is still part of the list
}
just fetch the object using SingleOrDefault and make related changes; you do not need to add it to the list again; you are simply changing the same instance which is an element of the list.
var temp = UserData.SingleOrDefault(s => s.ID == IDKey);
// apply changes
temp.X = someValue;
If I'm misunderstanding you then please correct me, but I think you're saying that you essentially want to iterate through the elements of a list, and if it matches a condition then you want to alter it in some way and add it to another list.
If that's the case, then please see the code below to see how to write an anonymous method using the Where clause. The Where clause just wants an anonymous function or delegate which matches the following:
parameters: ElementType element, int index -- return: bool result
which allows it to either select or ignore the element based upon the boolean return. This allows us to submit a simple boolean expression, or a more complex function which has additional steps, as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace StackOverflow
{
class Program
{
static void Main(string[] args)
{
int IDKey = 1;
List<SomeClass> UserData = new List<SomeClass>()
{
new SomeClass(),
new SomeClass(1),
new SomeClass(2)
};
//This operation actually works by evaluating the condition provided and adding the
//object s if the bool returned is true, but we can do other things too
UserData.Where(s => s.ID == IDKey).ToList();
//We can actually write an entire method inside the Where clause, like so:
List<SomeClass> filteredList = UserData.Where((s) => //Create a parameter for the func<SomeClass,bool> by using (varName)
{
bool theBooleanThatActuallyGetsReturnedInTheAboveVersion =
(s.ID == IDKey);
if (theBooleanThatActuallyGetsReturnedInTheAboveVersion) s.name = "Changed";
return theBooleanThatActuallyGetsReturnedInTheAboveVersion;
}
).ToList();
foreach (SomeClass item in filteredList)
{
Console.WriteLine(item.name);
}
}
}
class SomeClass
{
public int ID { get; set; }
public string name { get; set; }
public SomeClass(int id = 0, string name = "defaultName")
{
this.ID = id;
this.name = name;
}
}
}
Related
I need to return one row of List from my function Selectus.
So I pass to the function Selectus object that reflects database table fields and I need to return one row which match the parameter looking_for:
public static List<T> Selectus<T>(string looking_for)
{
//all select data
var db = OrmLiteBaza().Open();//opening database
var select_all_list = db.Select<T>();//getting all data for <T> object works fine
db.Dispose();
//try to select one row - here I have trouble:
var prop = typeof(T).GetProperties();//properties of passed <T> object
var list_selected_record = from records in select_all_list where prop[1].Name == looking_for select records;//tryin to select one record from <T> object as in looking_for variable
return list_selected_record.ToList();//here one record should be returned
}
I do not know how to select one row from the list assuming that T parameter is vary. In SelectusT> method I want to pass as T different objects which reflect fields in database table rather than creatinig separate methods for each select. e.g. call Selectus, where object passed is public class ProductCodes { public int ID { get; set; } public string SapIndex { get; set; } public string SapName { get; set; } }. Then I want to call another Selectus<ProductTypes> for another table etc... So I want to write generic/overall method and use it universally for all types of my objects which reflects the fields of few database tables. The SapIndex property is always in the same place of all objects...
Using prop[1] is incredibly fragile. Who says that the property you're currently interested in is always going to be in second place? What if someone adds another property tomorrow? What if not every T that you use have the same property in the second place on its list of properties? It is quite unclear what your actual goal is here and why you've taken the reflection route.
You would be better off using inheritance or interface implementation here. I'm going to use an interface in this answer, but either would work.
For the sake of clarity, let's assume there is a Code field in all your possible lists, and this is the property you're trying to match with.
Define a reusable interface:
public interface ICodeEntity
{
string Code { get; }
}
Apply your interface to all of the classes that you intend to use for your Selectus method.
public class Person : ICodeEntity
{
public string Code { get; set; }
// And other properties
}
public class Document : ICodeEntity
{
public string Code { get; set; }
// And other properties
}
Add a generic type constraint that limits the use of T only to types that implement your interface.
public static List<T> Selectus<T>(string code)
where T : ICodeEntity
You can now write your code in a way that it relies on the type in question having a Code property, and the compiler will help enforce it.
var db = OrmLiteBaza().Open();
var list = db.Select<T>().ToList();
db.Dispose();
return list.Where(item => item.Code == code).ToList();
Usage examples:
List<Person> peopleWithCodeABC = Selectus<Person>("ABC");
List<Person> documentsWithCodeXYZ = Selectus<Document>("XYZ");
// This will fail if Animal does not implement ICodeEntity
var compilerError = Selectus<Animal>("ABC");
I might not understand fully what you want, but instead of string looking_for you could pass in a Func<,> delegate which acts as a selector.
Something like:
public static List<TField> Selectus<T, TField>(Func<T, TField> selector)
{
var db = OrmLiteBaza().Open();
var select_all_list = db.Select<T>();
db.Dispose();
var list_selected_record = select_all_list.Select(selector); // 'using System.Linq;'
return list_selected_record.ToList();
}
Then I believe it could be called like this:
var list_one = Selectus((ProductCodes x) => x.SapIndex);
var list_two = Selectus((ProductTypes x) => x.SapIndex);
var list_three = Selectus((ProductCodes x) => x.SapName);
With this syntax I leave out the <ProductCodes, string> generic arguments to the method since they can be inferred.
Hmm, maybe you want it in the opposite dimension. You could do:
public static List<T> Selectus<T>(Func<T, bool> predicate)
{
var db = OrmLiteBaza().Open();
var select_all_list = db.Select<T>();
db.Dispose();
var list_selected_record = select_all_list.Where(predicate); // 'using System.Linq;'
return list_selected_record.ToList();
}
with:
var list_one = Selectus((ProductCodes x) => x.SapIndex == "ABC");
var list_two = Selectus((ProductTypes x) => x.SapIndex == "ABC");
var list_three = Selectus((ProductCodes x) => x.SapName == "DaName");
or:
var list_one = Selectus<ProductCodes>(x => x.SapIndex == "ABC");
var list_two = Selectus<ProductTypes>(x => x.SapIndex == "ABC");
var list_three = Selectus<ProductCodes>(x => x.SapName == "DaName");
But if it is going to always be the "same" property, like always x.SapIndex (but for different types of x), then Flater's answer looks good.
Otherwise, if you insist, your reflection approach should be possible. Use propety's name, not its index! Let me try:
public static List<T> Selectus<T>(string looking_for)
{
var db = OrmLiteBaza().Open();
var select_all_list = db.Select<T>();
db.Dispose();
const string prop_name = "SapIndex";
var prop = typeof(T).GetProperty(prop_name); // can blow up for bad T
var list_selected_record = select_all_list
.Where(x => (string)(prop.GetValue(x)) == looking_for); // 'using System.Linq;'
return list_selected_record.ToList();
}
with:
var list_one = Selectus<ProductCodes>("ABC");
var list_two = Selectus<ProductTypes>("ABC");
you can change code to return just one element
public static T Selectus<T>(string looking_for)
{
//all select data
var db = OrmLiteBaza().Open();//opening database
var select_all_list = db.Select<T>();//getting all data for <T> object works fine
db.Dispose();
//try to select one row - here I have trouble:
var prop = typeof(T).GetProperties();//properties of passed <T> object
var list_selected_record = from records in select_all_list where prop[1].Name == looking_for select records;//tryin to select one record from <T> object as in looking_for variable
return list_selected_record.FirstOrDefault();//here one record should be returned
}
I have a class
public class ABC
{
public int Id { get; set; }
public string Name { get; set; }
public Enum Msg { get; set; }
}
and collection of this class and single object
List<ABC> objColl = new List<ABC>();
ABC obj = new ABC();
Assume collection have items and i am trying to find single object which already exists in collection.
i want to find a single object inside that collection whether it exists or not.
I had already tried
var res = objColl.contains(obj);
it always return false. i dont want compare each property of object or loop.
Use Any with your criteria:
bool res = objColl.Any(s => s.Id == obj.Id);
if you want to use Contains then override Equals().
When you call Contains(), it searches for an item in the collection that is equal to the argument you've provided. Since you have not overridden Equals(), it uses the default implementation.
You have two options:
Override Equals() in class ABC to specify checking only the properties you want to check;
Use LINQ: objColl.Any(e => e.[some property] == obj.[some property])
You can use FirstOrDefault()
Returns the first element of a sequence, or a default value if no
element is found.
var res = objColl.FirstOrDefault(x => x.Id == obj.Id);
var res = objColl.Where(s=>s.Id == obj.Id).Any();
I have two classes like this
public class Stock
{
public StockItem Item;
public string Location;
public int Quantity;
public string Price;
}
public class StockItem
{
public string Code;
public string Name;
public string Unit;
}
And I have a list that contains multiple instances of the Stock class
var stockList = new List<Stock>();
I am trying to determine whether the Name property of each instance inside the list is equal to a predefined string. Currently, I am looping through the list like this
foreach (var stock in stockList)
{
if (stock.Item.Name.ToLower() == "test")
{
Console.WriteLine("Found the class")
break;
}
}
However, I was wondering if there was a more efficient way to do this using Linq or something similar to the .Contains method. Is there a simpler or more efficient way to accomplish this?
whether the Name property of each instance inside the list is equal
to a predefined string
Not much more efficient but simpler:
bool allAreEqual = stockList.All(x => x.Item.Name.Equals("test", StringComparison.OrdinalIgnoreCase))
If you instead want to find the first which matches the condition(what your loop really does):
Stock si = stockList.FirstOrDefault(x => x.Item.Name.Equals("test", StringComparison.OrdinalIgnoreCase));
Now you know if such a Stock exists(si != null) at all and you got it.
All in linq will return True or false
stockList.All(p => p.Item.Name.ToLower() == "test");
You can use the Linq Any() method:
bool containsItemName = stockList.Any(x => x.Item.Name.Equals("MyName", StringComparison.InvariantCultureIgnoreCase));
Are you really looking at all instances? From your question, it seems as if Anymight be the way to go, see here.
stockList.Any(p => p.Item.Name.ToLower() == "test");
You can get a result what you wanted by calling Any
bool result = stockList.Any(
stock => stock.Item.Name.Equals("text", StringComparison.InvariantCultureIgnoreCase)
);
In this code, the parameter name stock can be changed whatever you want.
I have the following list and class:
List<MyClass> MyList
public class MyClass
{
public int id { get; set; }
public bool checked { get; set; }
}
I also have the two variables:
int idToFind = 1234;
bool newcheckedvalue = true;
What I need to do is search the list and find the MyClass object where the id equals that value of idToFind. Once I have the object in the list, I then want to change the value of the checked property in the class to that of the newcheckedvalue value.
LINQ seems to be the solution to this problem, I just can't get the expression right. Can I do this in a single LINQ expression?
LINQ is for querying collection, not for modification. You can find the object like:
var item = MyList.FirstOrDefault(r=> r.id == idtoFind && r.checked == newcheckedvalue);
To find the item based on the ID only you can do:
var item = MyList.FirstOrDefault(r=> r.id == idtoFind);
Later you can set/modify its property.
//Make sure to check against Null, as if item is not found FirstOrDefault will return null
item.checked = newcheckedvalue; //or any other value
Example (to be noted that MyClass type has to be a class, a reference type, in this example):
var found = MyList.Where(ml=>ml.Id == 1234);
foreach(var f in found)
f.checked = newcheckedvalue;
I have varvariable called retVal which equals to some query. After some conditions I want to equate it to another query. But I get an error like implicit cast of type "System.Collections.Generic.IEnumerable<AnonymousType#1>" in "System.Collections.Generic.IEnumerable<AnonymousType#2>" is impossible. You can ask me why I don't want to define another var variable. Because this one is used in foreach cycle. Let's have a look on the code:
var retVal = from groupItem in result.AsEnumerable()
where groupItem.Sms.First().amountOfParts == (
(from item in rawSmsList.AsEnumerable()
where item.referenceNumber == groupItem.Sms.First().referenceNumber
select item).Count()
)
select new
{
Value = groupItem.Value,
Sms = groupItem.Sms
};
//CONDITION
if (retVal.ToArray().Length==0)
{
//HERE I NEED TO RETVAL EQUATE NEW QUERY
retVal = from groupItem in result.AsEnumerable()
where groupItem.Sms.First().amountOfParts == (
(from item in rawSmsList.AsEnumerable()
where item.senderNumber == groupItem.Sms.First().senderNumber
select item).Count()
)
select new
{
Value = groupItem.Value,
Sms = groupItem.Sms
};
}
foreach (var item in retVal)//FOREACH EXPECTS THE SAME RETVAL!!!
So how to cast different queries to the same var variable? Or how to find type of var variable and then cast it to a new defined variable?
var means implicitly typed variable, that means its type will be determined at compile time, So on your first usage it will be assigned an anonymous type, in your second you are trying to assign it a different anonymous type, you can't do that.
You can modify your code to use a class instead of anonymous object and then project to that, then you will be to do what you are doing now. You can create the class like:
public class MyClass
{
public int Value {get;set;}
public string Sms {get;set;}
}
and then project it by modifying your select statement as:
var retVal = ......
select new MyClass
{
Value = groupItem.Value,
Sms = groupItem.Sms
};
The anonymous class you're using for your projections looks the same to us, but they're two separate classes as far as the compiler is concerned, which is why you'll see AnonymousType#1 and AnonymousType#2 in the error.
One solution is to simply select "groupItem" instead of projecting with an anonymous class since you're only using properties within the groupItem itself. This would give you the same IQueryable type.
Side note: you should replace "retVal.ToArray().Length == 0" with "!retVal.Any()"
To add to Habib's answer:
Just create an actual class instead of using the anonymous type (which is a different class every time you use it). I don't know the types from your example so you'll have to specify:
public class ValueSmsThing // Give it a better name!
{
public IDontKnow Value { get; private set; } // specify the type!
public SmsNumber Sms { get; private set; } // !!
public ValueSmsThing( IDontKnow value, SmsNumber sms) {
Value = value;
Sms = sms;
}
}
And then in your query, instead of using the anonymous type:
select new
{
Value = groupItem.Value,
Sms = groupItem.Sms
};
Use the concrete class you created
select new ValueSmsThing( groupItem.Value, groupItem.Sms );
Then your for loop will know to iterate over ValueSmsThings.