How to print sorted list? - c#

I'm trying to sort a list of cars by their price range. Currently I'm unsure if I've even sorted it correctly with IComparable, and I can't figure out how I print the list after it's sorted, I can only print them in the order they were declared.
using System;
using System.Collections.Generic;
namespace Interface1
{
class Program
{
class Car : IComparable<Car>
{
public string Make { get; set; }
public string Model { get; set; }
public double Price { get; set; }
public int CompareTo(Car car)
{
return this.Price.CompareTo(car.Price);
}
static void Main(string[] args)
{
List<Car> cars = new List<Car>()
{
new Car(){Make = "Skoda", Model = "Fabia", Price = 50000},
new Car(){Make = "Skoda", Model = "Octavia", Price = 60000},
new Car(){Make = "Nissan", Model = "Juke", Price = 45000 }
};
foreach (var car in cars)
Console.WriteLine(car.Price);
}
}
}
}
Have I done the sorting correctly? How can I print it properly?

Change this line as so
foreach (var car in cars.OrderBy(x => x.Price))
Console.WriteLine(car.Price);
You can add a different comparer as well in the OrderBy function.

Related

How to add a object value to list<> in c# every time object created and print the list at the end

I am new to programming and trying to add object every time object created in list<>.
Customer obj = new Customer(name="abc",price=23);
Customer obj = new Customer(name="efg",price=45);
I want the price and name to add list and would like to sord price using Icomparable interface.
Can someone explain it please, Thank You
As per what i understood from your question, you can add a static List into your Customer class and add the price into your list inside the constructor. So every time you create an object of the class, the price will be added to your list.
Customer Class -
public class Customer
{
public string name { get; set; }
public int price { get; set; }
public static List<int> prices = new();
public Customer(string name, int price)
{
this.name = name;
this.price = price;
prices.Add(price);
}
}
When you are trying to print -
Customer obj = new Customer(name: "abc", price: 23);
Customer obj1 = new Customer(name: "efg", price: 45);
foreach (var price in Customer.prices)
{
Console.WriteLine(price);
}
Btw do you know how to compare objects using IComparable interface? I
am getting error as other.object is coming null.
I guess you want to compare the price i guess? If yes then id recommend you to do a generic list, the foreach loop adds each item from the string array into the list, where the Constructer is getting passed the line.
I "remodelled" your constructor a bit. For comparison you can use the interface IComparable (can also be used with IEnumerable) this is also easier to maintain for you in the future
using System; using System.Collections.Generic; using System.IO;
namespace ConsoleApp25
{
class Program
{
static void Main(string[] args)
{
string[] lines = {"abc;23","efg;45" };
Customer[] customers = ReadFromStrArr(lines);
Console.WriteLine(customers[0].price.CompareTo(customers[1].price));
}
static Customer[] ReadFromStrArr(string[] lines)
{
if (lines == null)
throw new ArgumentNullException(nameof(lines));
var result = new List<Customer>();
foreach (var line in lines)
{
result.Add(new Customer(line));
}
return result.ToArray();
}
}
public class Customer : IComparable<int>
{
public string name { get; set; }
public int price { get; set; }
public Customer(string line)
{
string[] data = line.Split(";");
name = data[0];
price = Convert.ToInt32(data[1]);
// prices.Add(price); // ??
}
public int CompareTo(int other)
{
return price.CompareTo(other);
}
}
}

CSV file has different rows

I have a csv file that looks like this:
M;2017.12.01 17:04;1;example#example.com
T;1;K001;2
T;1;N001;1
M;2017.11.01 15:56;2;example#example.com
T;2;P001;2
T;2;P001;1
My problem is that I have to read this file into a List<> and be able to navigate in it with indexes but the different types of rows after the long ones are confusing me.
class Order
{
public string Type { get; set; }
public DateTime Date { get; set; }
public string OrderID { get; set; }
public string Email { get; set; }
public string ItemNumber { get; set; }
public int Quantity { get; set; }
public Order(string[] ordered , string[] items)
{
Type = ordered[0];
Date = DateTime.Parse(ordered[1]);
OrderID = ordered[2];
Email = ordered[3];
Type = items[0];
OrderID = items[1];
ItemNumber = items[2];
Quantity = int.Parse(items[3]);
}
}
class Program
{
static List<Order> orders = new List<Order>();
static void Main(string[] args)
{
Reading();
}
private static void Reading()
{
using (System.IO.StreamReader reader = new System.IO.StreamReader("orders.csv"))
{
while (!reader.EndOfStream)
{
orders.Add(new Order(reader.ReadLine().Split(';') , reader.ReadLine().Split(';')));
}
}
}
}
You can try to identify the line before creating it.
Than you can create two different methods to initialize your order.
while (!reader.EndOfStream)
{
var values = reader.ReadLine().Split(';');
if(DateTime.TryParse(values.Skip(1).First(), out var date)) {
orders.Add(Order.FromOrderWithDate(values));
}
else
orders.Last().Items.Add(Item.FromOrderWithEmail(values));
}
The two methods will be something like
public static Order FromRow(string[] ordered) =>
new Order {
Type = ordered[0],
Date = DateTime.Parse(ordered[1]),
OrderID = ordered[2],
Email = ordered[3],
Items = new List<Item>();
};
public static Item FromRow(string[] items) =>
new Item {
Type = items[0],
OrderID = items[1],
ItemNumber = items[2],
Quantity = int.Parse(items[3])
};
And finally two different class, one for order and one for item, the Order should contain a list for the items.
Try something like:
List<Customer> customers = new List<Customer>();
Customer lastCustomer = null;
foreach(var line in File.ReadLines("orders.csv"))
{
var values = line.Split(';');
if (values[0]=="M")
{
lastCustomer = new Customer(values);
customes.Add(lastCustomer);
}
else if (values[0]=="T" && lastCustomer != null)
{
lastCustomer.AddOrder(values);
}
}
(you'll need to write a Customer class that can construct its self from an array of strings, plus has a method for adding new Order objects to its own list of orders, again constructing them from an array)

List object property as Key in LINQ GroupBy clause

Hey i want to ask if its possible to use List object property in GroupBy clausule:
MyProblem:
I want to group a list by a property directly from a list, and from object
which this list contains
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApp8
{
class ExampleDocument
{
public int idDoc { get; set; }
public List<Payments> payments { get; set; }
public string date { get; set; }
public ExampleDocument(int a, List<Payments> paymentss,string d)
{
idDoc = a;
payments = paymentss;
d = date;
}
}
class Payments
{
public int value { get; set; }
public string method { get; set; }
public Payments(int a, string b)
{
value = a;
method = b;
}
}
class Program
{
List<ExampleDocument> exampleList = new List<ExampleDocument>();
List<Payments> listOfPayments = new List<Payments>();
Payments a = new Payments(1000, "cash");
Payments b = new Payments(2000, "card");
void Work()
{
listOfPayments.Add(a);
listOfPayments.Add(b);
exampleList.Add(new ExampleDocument(1, listOfPayments,"2018-08-06"));
}
static void Main(string[] args)
{
Program c = new Program();
c.exampleList.GroupBy(p => new { p.date, ((Payments)p.payments).method });
}
}
}
"((Payments)p.payments).method }" here i got exception
Cannot convert type
'System.Collections.Generic.List' to
'ConsoleApp8.Payments'
ExampleList - contains commercial documents.
p.Example_VARIABLE - is the date of issue of the document.
Payments is class which contains property of payments
payments is a list of all payments (in document)
method is a payment method
As Cetin Bastoz answer i managed new query
namespace ConsoleApp8
{
class ExampleDocument
{
public int idDoc { get; set; }
public int DocNumber { get; set; }
public List<Payments> payments { get; set; }
public string date { get; set; }
public ExampleDocument(int a, int docNumber, List<Payments> paymentss, string d)
{
idDoc = a;
payments = paymentss;
DocNumber = docNumber;
date = d;
}
}
class Payments
{
public int payID { get; set; }
public int value { get; set; }
public string method { get; set; }
public Payments(int PayID, int a, string b)
{
payID = PayID;
value = a;
method = b;
}
}
class Program
{
List<ExampleDocument> exampleList = new List<ExampleDocument>();
List<Payments> listOfPayments = new List<Payments>();
void Work()
{
Payments a = new Payments(2, 1000, "cash");
Payments b = new Payments(1, 2000, "card");
listOfPayments.Add(a);
listOfPayments.Add(b);
exampleList.Add(new ExampleDocument(1, 20189, listOfPayments, "2018-08-06"));
exampleList.Add(new ExampleDocument(1, 201810, listOfPayments, "2018-08-08"));
exampleList.Add(new ExampleDocument(1, 201811, listOfPayments, "2018-08-09"));
}
static void Main(string[] args)
{
Program c = new Program();
c.Work();
var data2 = from d in c.exampleList
from p in d.payments
select new
{
Number = d.DocNumber,
DocDate = d.date,
payID = p.payID,
Amount = p.value
} into s
group s by s.DocDate into g
select g;
var sDocDate = "2018-08-06";
var result = data2.Select(x => x.Where(p => p.DocDate.Equals(sDocDate)));
Console.ReadKey();
}
}
}
Everthing is clear, untill i want to compare date2 result to date given from string
var sDocDate = "2018-01-21"
var result = data2.Select(x => x.Where(p => p.DocDate.Equals(sDocDate)));
Why at bottom image "result" got those "1,2,3 variable without entries"
You would use OfType<>() to get ExampleObject types from an ArrayList (I thought nobody left still using ArrayList):
var grouped = exampleList.OfType<ExampleObject>()
.GroupBy(p => new { p.EXAMPLE_VARIABLE, p.ExampleProperty});
EDIT: Although your code is faulty, after correcting it:
var data = from d in exampleList
from p in d.payments
group p by new {DocDate=d.date, PayType=p.method} into g
select g;

How to destruct a List element that contains three lists, so I can create a list to add to database

What is coming in to the webAPI is this JSON string and becomes deserilized in to this:
List<AddAssignMealView> mealtraiDeserializeObjects = JsonConvert.DeserializeObject<List<AddAssignMealView>>(mealTrainee);
mealtraiDeserializeObjects contains five index's one for each day of the week. Inside that specific index is a class that looks like what is below:
public class AddAssignMealView
{
public int TraineeID { get; set; }
public string DayOfTheWeek { get; set; }
public List<string> MealTypes { get; set; }
public List<int> MealID { get; set; }
public List<string> MealName { get; set; }
}
What I am trying to do is, be able to create a list of MealTrainee(Entity Framework):
public partial class MealTrainee
{
public int MealTraineeID { get; set; } //Ignore this one due to it being a post
public int MealID { get; set; }
public int TraineeID { get; set; }
public string DayOfTheWeek { get; set; }
public string MealType { get; set; }
public string MealName { get; set; }
public virtual Meal Meal { get; set; }
}
So I can be able to use addrange and add the list to the database. I understand how to use zip and combined two list types together if it is a single element. This is different due to it being a list of five elements and each of those five elements containing three lists. If someone could point me in the right direction, that would be helpful.
You can Zip 2 times to combine values from 3 lists into series of tuples. You can use SelectMany to flatten results. For example:
var result = mealtraiDeserializeObjects.SelectMany(c =>
c.MealID.Zip(c.MealName, (id,name) => new {id, name})
.Zip(c.MealTypes, (prev, type) => new {prev.id, prev.name, type})
.Select(r => new MealTrainee
{
TraineeID = c.TraineeID,
DayOfTheWeek = c.DayOfTheWeek,
MealID = r.id,
MealName = r.name,
MealType = r.type,
}));
This is the solution I found. I took it day by day in the sense that the first iteration would be Monday and then the count of meals(Ex:Meal for breakfast, Meal for Lunch) and put them in a count which would be "mealweek". Then I took mealweek and created a new mealtrainee for each count. Then after I made the meal out of the mealtrainee I put it in db.MealTrainees.AddRange and posted all the records.
[ResponseType(typeof(MealTrainee))]
public IHttpActionResult PostMealTrainee([FromBody] string mealTrainee)
{
List<MealTrainee> meals = new List<MealTrainee>();
using (DbContextTransaction dbContextTransaction = db.Database.BeginTransaction())
{
try
{
List<AddAssignMealView> mealtraiDeserializeObjects = JsonConvert.DeserializeObject<List<AddAssignMealView>>(mealTrainee);
foreach (var mealtraiDeserializeObject in mealtraiDeserializeObjects)
{
var mealWeek = mealtraiDeserializeObject.MealID.Select((m, i) => new
{
mealtraiDeserializeObject.TraineeID,
mealtraiDeserializeObject.DayOfTheWeek,
MealID = m,
MealTypes = mealtraiDeserializeObject.MealName[i],
MealName = mealtraiDeserializeObject.MealTypes[i]
}).ToList();
var meal = mealWeek.Select(x => new MealTrainee()
{
DayOfTheWeek = x.DayOfTheWeek,
MealID = x.MealID,
MealName = x.MealName,
MealType = x.MealTypes,
TraineeID = x.TraineeID
}).ToList();
db.MealTrainees.AddRange(meal);
}
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.SaveChanges();
dbContextTransaction.Commit();
return Ok(meals);
}
catch (Exception e)
{
dbContextTransaction.Rollback();
Logger.Log(e);
return BadRequest();
}
}
}

Get values from a HashSet<T> using reflection

I need a way to get the values from a generic HashSet using reflection. Here is what I've tried (you can copy/paste this on a console app):
class Program
{
public class Order
{
public int Id { get; set; }
}
public class Person
{
public string Name { get; set; }
public ICollection<Order> Orders { get; set; }
}
static void Main(string[] args)
{
var person = new Person();
person.Name = "Test Person";
person.Orders = new HashSet<Order>();
person.Orders.Add(new Order() { Id = 1 });
person.Orders.Add(new Order() { Id = 2 });
var reflectedOrders = person.GetType().GetProperty("Orders").GetValue(person, null);
Console.WriteLine("How do I iterate the reflected orders?");
Console.ReadLine();
}
}
EDIT
It's an example, in the real application I don't know which type to convert the reflected Orders. I only know the property is an ICollection<T> (turned to HashShet by EF)
Did you tried casting reflectedOrders to IEnumerable?
IEnumerable reflectedOrders = (IEnumerable)person.GetType().GetProperty("Orders").GetValue(person, null);
It should be simple as casting:
var reflectedOrders = (HashSet<Order>) person.GetType().GetProperty("Orders").GetValue(person, null);
foreach (var order in reflectedOrders)
...
What about
var orders = persons.OfType<Person>().SelectMany(p => p.Orders);

Categories