I want to orderby on a List like:
public List<Person> personList { get; set; };
class Person
{
public string Name{ get; set; };
public List<Car> carList{ get; set; };
}
class Car
{
public string Name { get; set; };
public int PriceInMillions { get; set; };
}
I want to sort CarList of each PersonList such that CarList has BMW object(can be one or more) at top of list?
Input:
Person: Name: 'ABC'
List<Car>:{{"x",25},{"y",25},{"BMW",26},{"x",25},{"BMW",25}}
Person: Name: 'DEF'
List<Car>:{{"BMW",21},{"y",25},{"BMW",26},{"x",25},{"BMW",20}}
Required Output:
Person: Name: 'ABC'
List<Car>:{{"BMW",25},{"BMW",26},{"x",25},{"y",25},{"x",25}}
Person: Name: 'DEF'
List<Car>:{{"BMW",20},{"BMW",21},{"BMW",26},{"y",25},{"x",25}}
I tried to find the index of "BMW" and swap it with first index but it is not working.
List<Car> orderedCarList = person.carList.OrderBy(s => (s.Name == "BMW") ? 0 : 1).ToList();
person.carList = orderedCarList;
If you want to sort in-place, without creating a new list or cars for each person, you can do
foreach(Person p in personList)
{
p.carList.Sort((car1, car2) =>
-(car1.Name == "BMW").CompareTo(car2.name == "BMW"));
}
Here is working solution:
public List<Person> GetSortedList(List<Person> personList)
{
foreach (var person in personList)
{
person.CarList=person.CarList.OrderByDescending(x => x.Name== "BMW").ToList();
}
return personList;
}
Related
How can I get all data from a nested list in C#?
Each person can have multiple cars.
Now I have a list of people and each item has a list of cars.
public class Person
{
public string FullName { get; set; }
public List<Car> Cars { get; set; }
}
public class Car
{
public string Name { get; set; }
}
And values:
var people = new List<Person>()
{
new Person()
{
FullName = "Jack Lee",
Cars = new List<Car>()
{
new Car()
{
Name = "BMW"
},
new Car()
{
Name = "Tesla"
}
}
},
new Person
{
FullName = "Micheal doug",
Cars = new List<Car>()
{
new Car()
{
Name = "Ferrari"
}
}
}
};
What is the best way to get all car names with one query?
Is it possible to get all cars with one query?
With System.Linq, you can use .SelectMany() to flatten the Cars lists from the people list and get the Name.
using System.Linq;
var result = people.SelectMany(x => x.Cars)
.Select(x => x.Name)
.ToList();
Demo # .NET Fiddle
I have the classes:
public class Person
{
public string Name{get;set;}
public bool IsMarried{get;set;}
public List<Child> Children { get; set; }
}
public class Child
{
public bool Greater5 { get; set; }
public List<MyColor> ListColor { get; set; }
}
public class MyColor
{
public string History { get; set; }
public string Type { get; set; }
}
I want to obtain a list string (MyColor.Type which are not empty) for all persons where IsMarried=true and Children.Greater5 = true.
I can achieve this with:
List<Person> list = personList.Where(l => l.IsMarried == true).ToList();
List<Child> childList = list.SelectMany(c => c.Children).Where(test => test.Greater5 == true).ToList();
List<string> wantedList= childList.SelectMany(test => test.ListColor.Where(c => !String.IsNullOrEmpty(c.Type)).Select(t => t.Type)).ToList();
but I was wondering if it could be achieved using Linq to be more simpler?
You can chain SelectMany to flatten nested children.
List<string> wantedList = personList
.Where(person => person.IsMarried)
.SelectMany(person => person.Children
.Where(child => child.Greater5)
.SelectMany(child => child.ListColor
.Where(color => !String.IsNullOrEmpty(color.Type))
.Select(color => color.Type)))
.ToList();
You also could use query language if that looks "simpler" to you:
List<string> wantedList = (from person in personList where person.IsMarried
from child in person.Children where child.Greater5
from color in child.ListColor where !string.IsNullOrEmpty(color.Type)
select color.Type).ToList();
I have two class :
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public bool isActif { get; set; }
public Product[] Product { get; set; }
}
public class Product
{
public string Id { get; set; }
}
And two instances :
Customer Customer1 = new Customer
{
FirstName = "FirstName1",
LastName = "LastName1",
isActif = true,
Product = new Product[]
{
new Product()
{
Id = "1"
}
}
};
Customer Customer2 = new Customer
{
FirstName = "FirstName2",
LastName = "LastName2",
isActif = false,
Product = new Product[]
{
new Product()
{
Id = "2"
}
}
};
I have one method who compare all properties of the two instances :
But when I get to the property Product, I have an StackOverflowException generated. Why ? And how to loop the property if it's a array ?
EDIT : When I use the List there is not StackOverflowException but System.Reflection.TargetParameterCountException. How to loop the property if it's a array
in:
foreach (PropertyInfo propertyInfo in
objectType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(x => x.CanRead))
Change your where condition for:
.Where(x => x.CanRead && x.Name != "SyncRoot")
SyncRoot documentation
If you do:
Console.WriteLine(Customer1.Product.Equals(Customer1.Product.SyncRoot));
You will see that Customer1.Product is equal to its SyncRoot property.
Therefore, when you use your AreEquals method on the Product Property, you will reach the SyncRoot property, which is the same than Product Property.
Then you will never be able to leave the loop. (Because SyncRoot has a SyncRoot property pointing on itself)
I'm having a tough time figureing out how to use the ForEach (or not use it) to print out the Car list I have inside the Parent list. I know obviously I can't do XmlData.p.b.ForEach and that the code below is just an example, as I'm going to have to do a lot of manipulation, but I just need to know how I can access the list in b inside the list p.
public static void Main(string[] args)
{
XmlSerializer deserializer = new XmlSerializer(typeof(Address));
TextReader reader = new StreamReader("myXML.xml");
object obj = deserializer.Deserialize(reader);
Address XmlData = (Address)obj;
reader.Close();
XmlData.p.ForEach(p => Console.WriteLine("Item in p!");
XmlData.p.b.ForEach(b => Console.WriteLine("Item in b!"); // can't do this
}
XML Format:
Top: MyRoot
----------Target
-----------------Parent
----------------------------Cars
[XmlRoot("MyRoot")]
public class MyRoot
{
[XmlElement("Dealership")]
public String dealership;
[XmlElement("ZipCode")]
public String zipCode;
[XmlArray("Targets")]
[XmlArrayItem("Parent")]
public List<Parent> p = new List<Parent>();
}
public class Parent : Student
{
[XmlElement("ParentName")]
public String parentName { get; set; }
}
public class Student
{
[XmlElement("Owner")]
public String owner { get; set; }
[XmlElement("Age")]
public String age { get; set; }
[XmlElement("Name")]
[XmlArrayItem("Cars")]
public List<Cars> c = new List<Cars>();
}
public class Cars
{
[XmlElement(Namespace="BuildDependency/CarYear")]
public String carYear { get; set; }
[XmlElement(Namespace = "BuildDependency/CarMake")]
public String carMake { get; set; }
[XmlElement(Namespace = "BuildDependency/CarModel")]
public String carModel { get; set; }
[XmlElement("CarColor")]
public String carColor { get; set; }
[XmlElement("CarMileage")]
public String carMileage { get; set; }
}
You could flatten the list using SelectMany:
XmlData.p.SelectMany(p => p.b).ToList()
.ForEach(b => Console.WriteLine("Item in b!"));
If you wish to iterate a list that is inside another list easy, you can do it within the first list iteration scope, something like (not gonna use lambda expressions but standard loops to keep it simple):
for(int i=0; i<XmlData.p.Length; i++) {
Console.WriteLine("Item in a!");
for(j=0; j<XmlData.p[i].b.Length; j++) {
Console.WriteLine("Item in b!");
}
}
Or you can just nest the second ForEach call:
XmlData.p.ForEach(outer => outer.b.ForEach(inner => Console.WriteLine("Item in b!")));
It's quite obvious that this doens't work, your code needs to be adapted so the b come's into the foreach class.
Your 2 nd call (iterating over list in list) should be:
XmlData.p.ForEach(p => p.c.ForEach(c => { Console.WriteLine("Item in C"); }));
I've written a very small demo project that I will share:
First some classes to make the project work:
public class MyRoot
{
public List<Student> p = new List<Student>();
}
public class Student
{
public List<Cars> c = new List<Cars>();
}
public class Cars
{
public String carYear { get; set; }
public String carMake { get; set; }
public String carModel { get; set; }
public String carColor { get; set; }
public String carMileage { get; set; }
}
Then the initiazization:
var cars = new List<Cars>();
cars.Add(new Cars());
cars.Add(new Cars());
cars.Add(new Cars());
cars.Add(new Cars());
var student = new List<Student>();
student.Add(new Student() { c = cars });
var root = new MyRoot();
root.p = student;
So we create 4 cars and 1 student with the 4 cars.
In the root object we set the list of students to just 1 student with the 4 cars.
So we have the following situation:
-- Root
-- Student
-- Car
-- Car
-- Car
-- Car
Now, to iterate over it, you need to do the following:
root.p.ForEach(p => Console.WriteLine("Item in 1"));
root.p.ForEach(p => p.c.ForEach(c => Console.WriteLine(" Item in 2")));
This will give the output:
Note: When you have 2 students, 1 student with 4 cars and the other one with 2 cars, the output will become:
This is because first we're iterating over the students and then over the cars.
When you see for each student it's cars, you can nest your foreach. Your foreach will then looks like:
root.p.ForEach(p =>
{
Console.WriteLine("Item in 1");
p.c.ForEach(c => Console.WriteLine(" Item in 2"));
});
And then your output will be:
So, fairly long post but I hope it helps.
I have created a List of type Students. The following classes are the ones I use;
public class StudentDetails
{
public class Address
{
public int HouseNumber{ get; set; }
public string LineOne{ get; set; }
public string LineTwo{ get; set; }
}
public class Student
{
public int StudentId { get; set; }
public Address StudentAddress{ get; set; }
}
public List<Student> GetStudents()
{
private Address StudentOne = new Address{//details};
private Address StudentTwo = new Address{//details};
var students = new List<Student>();
students.add(new Student {StudentId = 1, StudentAdress = StudentOne, //details});
//more students
return students;
}
}
Now I would like to access certain details of a particular student from this object. Say I want to get the House number of a student. How can i do that? I attempted to create another list, then add the list returned from GetStudents(). However when i iterate through it , i only get references to objects.
//To access the List
StudentDetails student = new StudentDetails(); //create new instance
for (int i = 0; i < student.GetStudents().Count; i++)
{
//Console.WriteLine(student[1].GetStudents());
}
You can use Linq to select the student you are searching for and then access its properties:
var student = GetStudents().FirstOrDefault(student => student.StudentId /* your student id here */>);
if (student != null)
{
var houseNumber = student.Address.HouseNumber;
}
Try this
StudentDetails student = new StudentDetails(); //create new instance
foreach (var s in student.GetStudents())
{
var id = s.StudentId;//use any properties using . operator
Console.WriteLine(s);
}
Console.WriteLine(GetStudents()[0].HouseNumber.ToString());
(0 can be whatever number)
or (gets a list of students and their house numbers) :
var houseNumbers = GetStudents().Select((student) =>
String.Format("Student: {0} - {1}",
student.StudentId, student.Address.HouseNumber));
foreach(var entry in houseNumbers) Console.WriteLine(entry);