Best way to get the lowest item in a list - c#

Situation: I got 3 classes that work with each other.
1: Main (the GUI)
2: Compare (to compare the values)
3: CompareData (inherits the list values)
I want to take two values: a string and a double, and put them in a list. Of course there will be more than just one list item at the end. After the list got filled, I'd like to get the lowest double with it's string and put them in a label.
Here is what I've got so far:
Main:
public class GlobaleDaten //The second List: VglDaten is the one for my situation
{
public static List<Daten> AlleDaten = new List<Daten>();
public static List<Vgl> VglDaten = new List<Vgl>();
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
[...Some Code thats not relevant...]
//addListAb adds values in a ListBox and should also
//place them into the list VglDaten
public void addListAb()
{
listBox.Items.Add(Abzahlungsdarlehenrechner.zgName + " " + "[Abzahlungsdarlehen]" + " " +Abzahlungsdarlehenrechner.zmErg.ToString("0.00") + "€" + " " + Abzahlungsdarlehenrechner.zgErg.ToString("0.00") + "€");
Vgl comp = new Vgl();
comp.name = Abzahlungsdarlehenrechner.zgName;
comp.gErg = Abzahlungsdarlehenrechner.zgErg;
GlobaleDaten.VglDaten.Add(comp);
}
//bVergleich should compare these values from the list
//and show the lowest value in a label
public void bVergleich_Click( object sender, RoutedEventArgs e)
{
if (listBox.Items.Count <= 0)
{
MessageBox.Show("Bitte erst Einträge hinzufügen.");
}
else
{
VglRechner vglr = new VglRechner();
vglr.Compare();
lVergleich.Content = VglRechner.aErg + " " + "€";
}
}
CompareData:
//Only used for storing the values
public class Vgl : Window
{
public string name { get; set; }
public double gErg { get; set; }
}
Compare:
public class VglRechner
{
public static string aName;
public static double aErg;
public void Compare(Vgl comp)
{
//I'm not sure if this is the right way to compare the values
//correct me if I'm wrong please :)
double low = GlobaleDaten.VglDaten.Min(c => comp.gErg);
aErg = low;
aName = comp.name;
}
}

Using Enumerable.Min is the right way to get the lowest value but you won't get the string which belonged to that value in this way, so the Vgl instance.
You could use this approach:
Vgl lowestItem = GlobaleDaten.VglDaten.OrderBy(c => c.gErg).First();
aErg = lowestItem.gErg;
aName = lowestItem.name;

Related

How to pass value in ArrayList from method to method

public Program()
{
amount_bike = new ArrayList();
}
public void push(int value)
{
this.amount_bike.Add(value);
}
public int amount_bike_pop()
{
if (this.amount_bike.Count == 0)
{
return -100000;
}
int lastItem = (int)this.amount_bike[this.amount_bike.Count - 1];
this.amount_bike.RemoveAt(this.amount_bike.Count - 1);
return lastItem;
}
public static void Bike_status()
{
bool exit = false;
Program available = new Program();
available.push(0);
available.push(0);
available.push(50);
WriteLine("E-bike available for rent is : " + available.amount_bike_pop() + " bikes.");
WriteLine("Rented E-bike is : " + available.amount_bike_pop() + " bikes.");
WriteLine("Broke E-bike is : " + available.amount_bike_pop() + " bikes.");
WriteLine("\n");
WriteLine("Please enter a number: 1 is back to pervoius menu or 0 to Exit");
int input = Convert.ToInt32(ReadLine());
while (exit == false)
{
if (input == 1)
{
Clear();
exit = true;
continue;
}
else if (input == 0)
{
Clear();
Exit();
}
else
{
Clear();
Bike_status();
}
}
}
public static void Add_bike()
{
}
I study data structures and Algorithms. In this code, I keep the value in an ArrayList named "available" in the Bike_status method. I need to pass a value in an ArrayList to the Add_bike method. How do I pass a value from one method to another? Actually, I need to pass valus such as 50 to plus some number that I push in Console.ReadLine.
Try to slow down.at starting point of programming sometimes it's confusing.
How do I pass a value from one method to another?
The simple answer is easy ,you want something to use in the function then in your method(s) you create parameter and pass the things you want to it.
like
//edit method to get int value -> public static void Bike_status()
public static void Bike_status(int value)
//edit when to call
else
{
Clear();
Bike_status(input);//send int value in
}
But really, what is that do you really want to learn?
if it OOP? I recommend you study this
https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/object-oriented/
To put it simply you has bicycle shop class separate from main program then use the method in that class
e.g.
//bicycle class
public class Bicycles{
public int ID {get;set;}
pulibc string status {get;set; }
public Bicycles(int p_id, string p_status)
{
ID = p_id;
status=p_status;
}
}
//bicycle shop class
public class BicyclesShop{
public List<Bicycle> available {get;set;} // class member
public BicyclesShop() // go search keyword "constructor"
{
available = new List<Bicycle> ();
}
//other method
public void Add_bike()
{
// I can access available object !
// do anything with this class member(s) !
}
public void Bike_status(int inputVal)
{
// do something with inputVal , change some properties?
}
//other methods
public int amount_bike_pop()
{
return available.Count();
}
public int amount_bike_broken_pop()
{
return available.Where(o=>o.status =="Broken").Count(); // go search linq
}
}
//To use in Main program method
BicyclesShop bs =new BicyclesShop();
bs.available.Add( new Bicycle(1 ,"OK") ); //add bicycle #1 in list
bs.available.Add( new Bicycle(2),"Broken" ); //add bicycle #2 in list
WriteLine("Broke E-bike is : " + bs.amount_bike_broken_pop() + " bikes.");

Get top 5 scores/names from list

I am adding a function to keep track of scores for a small game I made.
I want to get the top 5 scores (including name for that score) from a file that contains the scores.
The format of the saved scores is:
[name]-[score]
The scores and names are stored in 2 lists, which I parse this way:
string scores = File.ReadAllText(Environment.GetEnvironmentVariable("TEMP") + "/scores");
string[] splitscores = scores.Split('\n');
foreach (string entry in splitscores)
{
string replace = entry.Replace("[", "").Replace("]", "");
string[] splitentry = replace.Split('-');
if (splitentry.Count() > 1)
{
scorenames.Add(splitentry[0]);
scorelist.Add(Int32.Parse(splitentry[1]));
}
}
Then I retrieve #1 player by using:
int indexMax
= !scorelist.Any() ? -1 :
scorelist
.Select((value, index) => new { Value = value, Index = index })
.Aggregate((a, b) => (a.Value > b.Value) ? a : b)
.Index;
lblhighscore1.Text = "#1: " + scorelist[indexMax] + " by " + scorenames[indexMax];
How can I set the remaining 4 players assuming this is my scorelist:
[broodplank]-[12240]
[flo]-[10944]
[bill]-[11456]
[tony]-[9900]
[benji]-[7562]
I've figured I could do a descending sort of the score list, but that wouldn't cover the changes in the indexes of the usernames list, what is the best approach for this?
Best approach? Don't use parallel collections anti-pattern.
Instead of having 2 lists, create a class that can hold both the name and the score together
class Score
{
public string Name { get; private set; }
public int Score { get; private set; }
public Score(string name, int score)
{
Name = name;
Score = score;
}
}
and have just one list
List<Score> scores = new List<Score>();
foreach (string entry in splitscores)
{
string replace = entry.Replace("[", "").Replace("]", "");
string[] splitentry = replace.Split('-');
if (splitentry.Count() > 1)
{
scores.Add(new Score(splitentry[0], Int32.Parse(splitentry[1]))
}
}
You can easily order by one property and because the whole object will be reordered you'll keep the names in the right order without any additional code:
topScores = scores.OrderByDescending(x => x.Score).Take(5);
In addition to MarcinJuraszeks useful answer, some small things that I came across using his solution which I decided to share.
First problem was with the class which threw me the following error
'Score': member names cannot be the same as their enclosing type
Changing the case of "s" fixed it
class Score
{
public string Name { get; private set; }
public int score { get; private set; }
public Score(string name, int Score)
{
Name = name;
score = Score;
}
}
And calling the individual values can be done with Linq
string numberOne = topScores.Skip(0).First().score
string numberTwo = topScores.Skip(1).First().score
and so on

Can't figure out why Object reference is null

Working on a program for class, and am about 95% complete, but have run into a roadblock. I've got a Flight class that holds information about the flight, as well as a seating chart. Using a windows form listbox to select from the flight objects I created by reading from a text file. I can get values for every property from the class object, except for one, SeatChart.
Here's the pertinent code in the main program:
private void lstFlights_SelectedIndexChanged(object sender, EventArgs e)
{
curFlight = (Flight)lstFlights.SelectedItem;
DisplayNewFlightChart();
}
private void DisplayNewFlightChart()
{
int seats = curFlight.Rows * curFlight.Seats;
lstSeatingChart.Items.Clear();
string[] seatChart = curFlight.SeatChart;
for (int x = 0; x <= seats; x++)
{
lstSeatingChart.Items.Add("Seat " + (x + 1) + " " + seatChart[x]);
}
}
And here is the code from the class:
class Flight
{
private string mPlane;
private string mDepartureTime;
private string mDestination;
private int mRows;
private int mSeats;
private string[] mSeatChart;
public Flight()
{
}
// Create the overloaded Constructor
public Flight(string planeType, string departureTime,
string destination, int numRows,
int numSeatsPerRow)
{
this.Plane = planeType;
this.DepartureTime = departureTime;
this.Destination = destination;
this.Rows = numRows;
this.Seats = numSeatsPerRow;
this.SeatChart = mSeatChart;
mSeatChart = new string[Rows * Seats];
for (int seat = 0; seat <= mSeatChart.GetUpperBound(0); seat++)
{
mSeatChart[seat] = "Open";
}
}
public string Plane
{
get { return mPlane; }
set { mPlane = value; }
}
public string DepartureTime
{
get { return mDepartureTime; }
set { mDepartureTime = value; }
}
public string Destination
{
get { return mDestination; }
set { mDestination = value; }
}
public int Rows
{
get { return mRows; }
set { mRows = value; }
}
public int Seats
{
get { return mSeats; }
set { mSeats = value; }
}
public string[] SeatChart
{
get { return mSeatChart; }
set { mSeatChart = value; }
}
public void MakeReservation(string passName, int seat)
{
bool seatTaken = false;
if (mSeatChart[seat] != "Open") seatTaken = true;
if (passName != "" && seatTaken == false)
{
mSeatChart[seat] = passName;
}
else
{
MessageBox.Show("Please Enter a Passenger Name, in an unreserved seat");
}
}
It's telling me the curFlight.SeatChart is null, even though I can pull .Rows and .Seats from the curFlight just fine. I have no clue why .SeatChart is messing up. lstFlights is the list of flight objects pulled from the text file, and lstSeatingChart is where I want to display a list of seats.
You are setting SeatChart to mSeatChart, which is null at that time. So no reference to an object is made for this.SeatChart.
After that you initialize mSeatChart and fill it.
You should move setting this.SeatChart after initializing mSeatChart.
mSeatChart = new string[Rows * Seats];
this.SeatChart = mSeatChart;
Edit:
In addition, SeatChart is the property and mSeatChart is the member variable. SeatChart will be used to expose mSeatChart, so it's really weird to set SeatChart with mSeatChart. So weird that I didn't even think you were doing that.
So in your case leave the following out in the constructor:
this.SeatChart = mSeatChart;
I think the actual cause of your issue is somewhere else in the code, where you initiate Flight and fill the list. If I understand correctly you get a null reference error on the concatenation in the for loop?
string[] seatChart = curFlight.SeatChart;
for (int x = 0; x <= seats; x++)
{
lstSeatingChart.Items.Add("Seat " + (x + 1) + " " + seatChart[x]);
}
Check where you initate each Flight object. I bet you are using the empty constructor: new Flight()
Remove the empty constructor, because you don't expect empty values apparently. And if you really need the empty constructor then either initiate all member variables as expected or perform a null check wherever you want to use them.
And once you found the cause, make sure you change the for loop to
for (int x = 0; x < seats; x++)
since you are checking for the number of seats and do a zero-based loop. If x = seats you would have performed the loop seats + 1 times (rows*seats + 1).
If your code relies on a particular property never being null, you need to make sure it is initialized in all constructors.
Based on the logic of your class, I would suggest you shouldn't have a parameter less constructor. It doesn't make sense to have a flight that didn't have a known number of seats (in your implementation at least).
Also some style things.
You don't need to declare your private instance variables. Just use
public string destination {get; set;}
Declare "open" as a class constant and use that constant rather than the hard coded string value.

How to return ALL data members, not just slope and length

I'm curious as to how (if possible) to return ALL data members in my program by overriding ToString. The data members are the x and y coordinates as well as the beginning and ending points. Its probably just me missing something small but would appreciate some outside input, thank you.
namespace LineMath
{
class Program
{
static void Main(string[] args)
{
Point p1 = new Point(10, 5);
Point p2 = new Point(36, 18);
LineMath.Program.Point.Line LI1 = new LineMath.Program.Point.Line(p1, p2);
Console.WriteLine("Line Values");
Console.WriteLine("----------------");
Console.WriteLine((LI1.ToString()));
Console.WriteLine("----------------");
Console.WriteLine();
}
public class Point
{
private double xpoint;
private double ypoint;
public Point()
{
}
public Point(double xpointvalue, double ypointvalue)
{
xpoint = xpointvalue;
ypoint = ypointvalue;
}
public double X
{
get
{
return xpoint;
}
set
{
}
}
public double Y
{
get
{
return ypoint;
}
set
{
}
}
public class Line
{
private Point bp;
private Point ep;
private double li;
private double sl;
public Line()
{
}
public Line(Point a, Point b)
{
bp = a;
ep = b;
li = Math.Sqrt((Math.Pow((ep.X - bp.X), 2) + Math.Pow((ep.Y - bp.Y), 2)));
sl = (ep.Y - bp.Y) / (ep.X - bp.X);
}
public Point BP
{
set
{
}
}
public Point EP
{
set
{
}
}
public double LI
{
get
{
return li;
}
}
public double SL
{
get
{
return sl;
}
}
public override string ToString()
{
return "Slope = " + sl.ToString("F2") + "\n" + "\n" + "Length = " + li.ToString("F2");
}
}
}
}
}
The purpose of ToString() is to provide a string representation of an object instance that is in some way meaningful to you the programmer (often for debugging), or the users of your program.
You have access to all of the fields, properties and methods of the class and can create whatever string representation is meaningful to you from those.
return ALL data members in my program
A program typically consists of more than one class. ToString() acts on a given instance of a given class, not "an entire program". You may need to clarify what you mean by that part of your question.
If you want to return the data, and if you expect to do something with that data (besides display it), you should not use ToString() for that purpose.
UPDATE (based on your edit)
Look at the extra line I added. It shows one way to include your property BP. You can extend that for any other properties. Note too that you are using "\n\n" but probably mean "\r\n" for Windows environments. You can use Environment.NewLine to have the runtime handle the correct newline codes for you.
public override string ToString()
{
return "Slope = " + sl.ToString("F2") + "\n" + "\n" + "Length = " + li.ToString("F2")
Environment.NewLine + " BP (" + BP.X + ", " + BP.Y + ")";
}
Place a formula for slope and length, as value for SL and LI respectively
public double SL
{
get
{
if(bp == null || ep == null)
sl = 0.0;
else
//Formula for slope of a line
sl = (ep.Y - bp.Y) / (ep.X - bp.X);
return sl;
}
}
public double LI
{
get
{
//Use Euclidean distance to get length of line
if(bp == null || ep == null)
li = 0.0;
else
li = Math.Sqrt(Math.Pow(bp.X - ep.X, 2) + Math.Pow(bp.Y - ep.Y, 2));
return li;
}
}
public override string ToString()
{
//Something like this
return "Line1\nBegin Point: (" + bp.X + ", " + bp.Y + ")\nEnd Point: (" + ep.X + ", " + ep.Y + ")\n\nSlope = " + sl.ToString("F2") + "\n\n" + "Length = " + li.ToString("F2");
}
You can return more than value from a method by either using out parameters or creating a new data structure (a struct or class) to hold your return values. e.g.
private void GetXYBeginEnd(int a, int b, out int x, out int y, out int begin, out int end)
{
// assign your out params in here
}
OR:
class CalcResult
{
public int X { get; set; }
public int Y { get; set; }
public int Begin { get; set; }
public int End { get; set; }
}
private CalcResult GetXYBeginEnd(int a, int b, out int x, out int y, out int begin, out int end)
{
// do stuff
return new CalcResult { X = 23, Y = 54, Begin = 45, End = 98 };
}

Trying to make it so when i click on my windows forms button, the next 3 numbers from my textfile are shown

Here is the code below.
I am trying to make it so that when I click on the nextButton button it cycles to the next 3 numbers in my textfile. I cant figure out ow, what i have here should work :[
namespace GPSProject
{
class dataPoints
{
public int Count { get { return Points.Count; } }
List<dataPoint> Points;
//string p;
public dataPoints(/*string path*/)
{
Points = new List<dataPoint>();
// p = path;
TextReader tr = new StreamReader(/*p*/"C:/Test.txt");
string input;
while ((input = tr.ReadLine()) != null)
{
string[] bits = input.Split(',');
dataPoint a = new dataPoint(bits[0], bits[1], bits[2]);
Points.Add(a);
}
tr.Close();
}
internal dataPoint getItem(int p)
{
if (p < Points.Count)
{
return Points[p];
}
else
return null;
}
}
}
Above is the class that breaks down the textfile into inidividual numbers.
namespace GPSProject
{
public partial class Form1 : Form
{
private int count;
internal dataPoints myDataPoints;
public Form1()
{
myDataPoints = new dataPoints();
InitializeComponent();
}
private void buttonNext_Click(object sender, EventArgs e)
{
{
count++;
if (count == (myDataPoints.Count))
{
count = 0;
}
dataPoint a = myDataPoints.getItem(count);
textBoxLatitude.Text = a.CurLatitude;
textBoxLongtitude.Text = a.CurLongtitude;
textBoxElevation.Text = a.CurElevation;
}
}
}
}
Above is the Windows form
namespace GPSProject
{
class dataPoint
{
private string latitude;
private string longtitude;
private string elevation;
public dataPoint() //Overloaded incase no value available
{
latitude = "No Latitude Specified";
longtitude = "No Longtitude Specified";
elevation = "No Elevation Specified";
}
public dataPoint(string Latitude, string Longtitude, string Elevation)
{
// TODO: Complete member initialization
this.latitude = Latitude;
this.longtitude = Longtitude;
this.elevation = Elevation;
}
public string CurLongtitude { get { return this.longtitude; } }
public string CurLatitude { get { return this.latitude; } }
public string CurElevation { get { return this.elevation; } }
}
}
And finally this is the class the holds the numbers. The numbers i am trying to get the textboxes to show are cycles of CurLongtitude/Latitue/Elevation
First thing to do would be to create a proper vessle for your data: the DataPoint Entity:
class DataPoint
{
// Option 1: Field + read only property
private string _latitude;
public string Latitude { get { return _latitude; } }
// Option 2: Property + compiler generated field
public string Longitude { get; private set; }
public string Elevation { get; private set; }
// Constructor
public DataPoint(string latitude, string longtitude, string elevation)
{
// Internally in this class we use fields
_latitude = latitude;
// Unless we use property option 2
this.Longitude = longitude;
this.Elevation = elevation;
}
}
Next we could add a static method to the DataPoint class to load the data points from disk:
public static List<DataPoint> LoadFromFile (string filename)
{
// The .NET framework has a lot of helper methods
// be sure to check them out at MSDN
// Read the contents of the file into a string array
string[] lines = File.ReadAllLines(filename);
// Create the result List
List<DataPoint> result = new List<DataPoint>();
// Parse the lines
for (string line in lines)
{
string[] bits = line.Split(',');
// We're using our own constructor here
// Do watch out for invalid files, resulting in out-of-index Exceptions
DataPoint dataPoint = new DataPoint(bits[0], bits[1], bits[2]);
result.Add(dataPoint);
}
return result;
}
Now that we have all the building blocks. Let's make the application:
public partial class Form1 : Form
{
private int _index;
private List<DataPoint> _dataPoints;
public Form1()
{
// Since this is a simple test application we'll do the call here
_dataPoints = DataPoint.LoadFromFile(#"C:\Test.txt");
InitializeComponent();
}
private void buttonNext_Click(object sender, EventArgs e)
{
// Cycle the data points
_index++;
if (_index == _dataPoints.Count)
{
_index = 0;
}
// Get the specific data point
DataPoint dataPoint = _dataPoints[_index];
// The empty texts are UI only, so we could check them here
if (dataPoint.Latitude == null || dataPoint.Latitude == "")
{
textBoxLatitude.Text = "No Latitude Specified";
}
else
{
textBoxLatitude.Text = dataPoint.Latitude;
}
// A shorter, inline version
textBoxLongtitude.Text = String.IsNullOrEmpty(dataPoint.Longitude) ? "No Longitude Specified" : dataPoint.Longitude;
// Or if we don't care about empty texts
textBoxElevation.Text = dataPoint.Elevation;
}
}
Of course there are lots of ways to make the code even shorter, or to use modern techniques like LINQ, but I've tried not to go too far from your existing code. I haven't tried the code, I typed it here on SO :)
Also please be careful in how you format your code. Proper casing and following standards makes your code a lot easier to read by others.
MSDN has a lot of good examples and extensive documentation on the .NET Framework classes.

Categories