All the examples I see of using the IndexOf() method in List<T> are of basic string types. What I want to know is how to return the index of a list type that is an object, based on one of the object variables.
List<Employee> employeeList = new List<Employee>();
employeeList.Add(new Employee("First","Last",45.00));
I want to find the index where employeeList.LastName == "Something"
int index = employeeList.FindIndex(employee => employee.LastName.Equals(somename, StringComparison.Ordinal));
Edit: Without lambdas for C# 2.0 (the original doesn't use LINQ or any .NET 3+ features, just the lambda syntax in C# 3.0):
int index = employeeList.FindIndex(
delegate(Employee employee)
{
return employee.LastName.Equals(somename, StringComparison.Ordinal);
});
public int FindIndex(Predicate<T> match);
Using lambdas:
employeeList.FindIndex(r => r.LastName.Equals("Something"));
Note:
// Returns:
// The zero-based index of the first occurrence of an element
// that matches the conditions defined by match, if found;
// otherwise, –1.
you can do this through override Equals method
class Employee
{
string _name;
string _last;
double _val;
public Employee(string name, string last, double val)
{
_name = name;
_last = last;
_val = val;
}
public override bool Equals(object obj)
{
Employee e = obj as Employee;
return e._name == _name;
}
}
Sorry, one more for good measure :)
int index = employees.FindIndex(
delegate(Employee employee)
{
return employee.LastName == "Something";
});
Edit: - Full Example in .NET 2.0 Project.
class Program
{
class Employee { public string LastName { get; set; } }
static void Main(string[] args)
{
List<Employee> employeeList = new List<Employee>();
employeeList.Add(new Employee(){LastName="Something"});
employeeList.Add(new Employee(){LastName="Something Else"});
int index = employeeList.FindIndex(delegate(Employee employee)
{ return employee.LastName.Equals("Something"); });
Console.WriteLine("Index:{0}", index);
Console.ReadKey();
}
}
I prefer like this
private List<Person> persons = List<Person>();
public PersonService()
{
persons = new List<Person>() {
new Person { Id = 1, DOB = DateTime.Today, FirstName = "Pawan", LastName = "Shakya" },
new Person { Id = 2, DOB = DateTime.Today, FirstName = "Bibek", LastName = "Pandey" },
new Person { Id = 3, DOB = DateTime.Today, FirstName = "Shrestha", LastName = "Prami" },
new Person { Id = 4, DOB = DateTime.Today, FirstName = "Monika", LastName = "Pandey" },
};
}
public PersonRepository.Interface.Person GetPerson(string lastName)
{
return persons[persons.FindIndex(p=>p.LastName.Equals(lastName, StringComparison.OrdinalIgnoreCase))];
}
The answer is for those coming here to know why IndexOf()
doesn't work.
Your class must override Equals method of object possessing the following declaration.
public override bool Equals(object obj)
Related
I am developing micro-service with .NET Core.
The following code is working with an HttpPut request.
But if any field has empty or null value in our incoming JSON request, I want it to retrieve the previous value.
I don't want to constantly run the code below. Is there a short way around this?
if(updateCustomer.Surname != null && updateCustomer.Surname !=string.Empty)
{
customer.Surname = updateCustomer.Surname;
}
var serviceResponse = new ServiceResponse<GetCustomerDto>();
Customer customer = await _context.Customers.FirstOrDefaultAsync(c => c.Id == updateCustomer.Id);
var persons = (from p in _context.Customers where p.Id == updateCustomer.Id select p);
foreach (var person in persons)
{
person.Name = updateCustomer.Name;
person.Surname = updateCustomer.Surname;
person.BusinessCode = "123";
person.Phone = updateCustomer.Phone;
}
await _context.SaveChangesAsync();
serviceResponse.Data = _mapper.Map<GetCustomerDto>(customer);
Following the GetValueOrDefault() idiom from Nullable types, you can create a string extension method to select between two values like so:
public static class StringExtensions
{
public static string GetValueOrDefault(this string str, string alternative)
{
if(string.IsNullOrEmpty(str))
{
return alternative;
}
return str;
}
}
public class Program
{
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
public string BusinessCode { get; set; }
public string Phone { get; set; }
}
public static void Main()
{
Person previous = new Person
{
Name = null,
Surname = "Smith",
BusinessCode = "123",
Phone = "(555) 123-4567"
};
Person current = new Person
{
Name = "John",
Surname = string.Empty,
BusinessCode = "321",
Phone = "(555) 765-4321"
};
Person updated = new Person
{
Name = current.Name.GetValueOrDefault(previous.Name),
Surname = current.Surname.GetValueOrDefault(previous.Surname),
BusinessCode = current.BusinessCode.GetValueOrDefault(previous.BusinessCode),
Phone = current.Phone.GetValueOrDefault(previous.Phone)
};
}
}
In this code, the CompareTo() method is not called explicitly and the max() gives the correct result. So, my question is: Is it possible that CompareTo() is called implicitly/auto-call? If so, how would I know which other function/method could be called implicitly? Please help me understand, thank you!
Results : Steve
public class Student : IComparable<Student>
{
public int StudentID { get; set; }
public string StudentName { get; set; }
public int Age { get; set; }
public int StandardID { get; set; }
public int CompareTo(Student other)
{
if (this.StudentName.Length >= other.StudentName.Length)
return 1;
return 0;
}
}
class Program
{
static void Main(string[] args)
{
// Student collection
IList<Student> studentList = new List<Student>>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13} ,
new Student() { StudentID = 2, StudentName = "Moin", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20} ,
new Student() { StudentID = 5, StudentName = "Steve" , Age = 15 }
};
var studentWithLongName = studentList.Max();
Console.WriteLine("Student Name: {1}", studentWithLongName.StudentName);
}
}
As Jeroen already said, you are making a call to the IEnumerable.Max() method.
Basically what that function is doing "in the shadows" is something similar to this:
private static T Max<T>(IEnumerable<T> source) where T : IComparable<T>
{
if (source == null)
throw new ArgumentNullException(nameof(source));
bool isMaxSet = false;
T max;
foreach (T item in source)
{
if (isMaxSet == false)
{
max = item;
isMaxSet = true;
}
else
{
if (max.CompareTo(item) < 0) // here's where it's used!
max = item;
}
}
if (isMaxSet == false)
throw new InvalidOperationException();
return max;
}
Also, be careful as your int CompareTo(Student) function is incomplete and its use could cause unexpected results.
As specified in https://learn.microsoft.com/en-us/dotnet/api/system.icomparable.compareto?view=netframework-4.8, here's how it should work:
Less than zero: This instance precedes obj in the sort order.
Zero: This instance occurs in the same position in the sort order as obj.
Greater than zero: This instance follows obj in the sort order.
I have a list of Students in cache, and I wants to update an item, how can i do that.
public class Student
{
int id;
string name;
string address;
}
public void updateStudent(Student st)
{
var student = _cache.Get(CacheVariable.cache_data_student) as List<Student>;
//How to update student.
}
Maybe you can do it with a small query.
First Find this updated student is who?
And Find this student's place from List
Then Change This Place with new Value
var student = _cache.Get(CacheVariable.cache_data_student) as List<Student>;
Student findStudent = student.FirstOrDefault(x=> x.Id == st.Id);
int id = student.IndexOf(y);
student[id] = st;
or if you want you can use another thing for last row like :
student[id] = new Student()
{
id = x,
name = "y",
address = "z"
};
Probably there is a better solution for this situation but I don't know. I think this could be helpfull
Since the ID should be the unique identifier, use LINQ to get the student to update:
public void updateStudent(Student st)
{
Student studentToUpdate = _cache.FirstOrDefault(s => s.id == st.id)
studentToUpdate?.Update(st);
}
To update your student you need to implement your own method. Just set the properties like
public class Student
{
public int id { get; }
public string name { get; set; }
public string address { get; set; }
public void Update(Student st)
{
this.name = st.name;
this.address = st.address;
}
}
public class Student
{
int id;
string name;
string address;
}
public void updateStudent(Student st)
{
var student = _cache.Get(CacheVariable.cache_data_student) as List<Student>;
//First look for the st in Student list, you need the id field or primary key
var s = student.Where(x => x.idField == st.idField).FirstOrDefault();
s = st;
//student = st;//student.Update(st); //Not working. Only pass the value
}
I want to get the difference between two integers, in this case "Age" - subtract them.
Here my class and my list. I want to, with a method, take the age from Robin and Sara and show the age difference. Is this possible with LINQ or..?
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
public class LinqQuery
{
private readonly List<Person> _persons = new List<Person>
{
new Person {FirstName = "Robin", LastName = "Blixt", Age = 29},
new Person {FirstName = "Sara", LastName = "Johansson", Age = 44}
};
public IEnumerable<Person> GetAll()
{
return _persons;
}
public void difference()
{
?????
Console.ReadKey();
}
}
Thanks in advance.
You can use lambda expression to find specified index if FirstName is youre key and you have more items than two.
Please note that I did not check any erros (empty list etc.)
public void diff()
{
int indxRobin = lst.FindIndex((item) => { return item.FirstName == "Robin"});
int indxSara = lst.FindIndex((item) => { return item.FirstName == "Sara"});
return lst[indxRobin].Age - lst[indxSara].Age;
}
Using a cross-join you could calculate the age difference for all permutations in the list.
Of course, this is very crude and gives all duplicates, but it's easy from there to remove the duplicates in the query.
public void Difference()
{
var ageDifferences = from p1 in _persons
from p2 in _persons
select new
{
P1FullName = p1.FirstName + " " + p1.LastName,
P2FullName = p2.FirstName + " " + p2.LastName,
AgeDifference = Math.Abs(p1.Age - p2.Age)
};
foreach (var item in ageDifferences)
{
Console.Out.WriteLine("{0} and {1} have {2} years of age difference.", item.P1FullName, item.P2FullName, item.AgeDifference);
}
Console.ReadKey();
}
Thanks, #Tim Schmelter for the suggestion :)
public void difference()
{
int sara= _persons.FirstOrDefault(p=>p.FirstName=="Sara").Age;
int robin=_persons.FirstOrDefault(p=>p.FirstName=="Robin").Age;
int difference= Math.abs(sara-robin);
Console.ReadKey();
}
I have two lists (ListA and ListB), the type of these lists is the same PersonInfo, the Loginfield is a unique key.
public class PersonInfo
{
public string Login { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public bool Active { get; set; }
}
I'd like compare these two lists :
I'd like get a list of items in ListA not available in ListB
For the items available in both lists, I'd like get a list from ListA (Login field is a unique key) for the item where there is a difference between the two lists.
Example : if for the Login "MyLogin" in ListA, the value of FirstName does not match with the value in ListB. The item with "MyLogin" as Login must be part of the result list.
Example : if the Age between ListA and ListB for a specific login is different, the item must be part of the result
Thanks.
To compare objects of custom data type lists, you will need to implement IEquatable in your class and override GetHashCode()
Check this MSDN Link
Your class
public class PersonInfo : IEquatable<PersonInfo>
{
public string Login { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public bool Active { get; set; }
public bool Equals(PersonInfo other)
{
//Check whether the compared object is null.
if (Object.ReferenceEquals(other, null)) return false;
//Check whether the compared object references the same data.
if (Object.ReferenceEquals(this, other)) return true;
//Check whether the properties are equal.
return Login.Equals(other.Login) && FirstName.Equals(other.FirstName) && LastName.Equals(other.LastName) && Age.Equals(other.Age) && Active.Equals(other.Active);
}
public override int GetHashCode()
{
int hashLogin = Login == null ? 0 : Login.GetHashCode();
int hashFirstName = FirstName == null ? 0 : FirstName.GetHashCode();
int hashLastName = LastName == null ? 0 : LastName.GetHashCode();
int hashAge = Age.GetHashCode();
int hashActive = Active.GetHashCode();
//Calculate the hash code.
return (hashLogin + hashFirstName + hashLastName) ^ (hashAge + hashActive);
}
}
Then here is how you use it (as listed in Pranay's response)
List<PersonInfo> ListA = new List<PersonInfo>() { new PersonInfo { Login = "1", FirstName = "James", LastName = "Watson", Active = true, Age = 21 }, new PersonInfo { Login = "2", FirstName = "Jane", LastName = "Morrison", Active = true, Age = 25 }, new PersonInfo { Login = "3", FirstName = "Kim", LastName = "John", Active = false, Age = 33 } };
List<PersonInfo> ListB = new List<PersonInfo>() { new PersonInfo { Login = "1", FirstName = "James2222", LastName = "Watson", Active = true, Age = 21 }, new PersonInfo { Login = "3", FirstName = "Kim", LastName = "John", Active = false, Age = 33 } };
//Get Items in ListA that are not in ListB
List<PersonInfo> FilteredListA = ListA.Except(ListB).ToList();
//To get the difference between ListA and FilteredListA (items from FilteredListA will be removed from ListA)
ListA.RemoveAll(a => FilteredListA.Contains(a));
EDIT
Try this soltuion for detail difference :
Compare two objects and find the differences
How to: Find the Set Difference Between Two Lists (LINQ)
Enumerable.Except Method (IEnumerable, IEnumerable) -Produces the set difference of two sequences by using the default equality comparer to compare values.
double[] numbers1 = { 2.0, 2.1, 2.2, 2.3, 2.4, 2.5 };
double[] numbers2 = { 2.2 };
IEnumerable<double> onlyInFirstSet = numbers1.Except(numbers2);
or
//newList will include all the common data between the 2 lists
List<T> newList = list1.Intersect(list2).ToList<T>();
//differences will be the data not found
List<T> differences = list1.RemoveAll(a => newList.Contains(a));
or
outer join to get difference
var compare1to2 = from a in
from b in driveList2.Where(b => b.property == a.property).DefaultIfEmpty()
select a;
var list3 = list1.Except(list2).ToList(); //List3 contains what in list1 but not _list2.
Try this for objects comparison and loop around it for List<T>
public static void GetPropertyChanges<T>(this T oldObj, T newObj)
{
Type type = typeof(T);
foreach (System.Reflection.PropertyInfo pi in type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance))
{
object selfValue = type.GetProperty(pi.Name).GetValue(oldObj, null);
object toValue = type.GetProperty(pi.Name).GetValue(newObj, null);
if (selfValue != null && toValue != null)
{
if (selfValue.ToString() != toValue.ToString())
{
//do your code
}
}
}
}
you can use Zip() and Intersect() from LINQ