Array sorting by class property in c# [duplicate] - c#

Hope someone can help.
I have created a variable length array that will accept several name inputs.
I now want to sort the array in alphabetical order and return that to the console screen.
I thought that Array.Sort(names); would do this for me but I am getting an exception thrown. I have been looking at notes, examples and on-line but nothing seems to match what I am doing.
I have done the below so far. I am close to tearing my hair out here!
PS I have been trying to figure this out for hours and I am 30+ years old trying to learn myself, so please don't just say "Do your homework" I have tried to resolve this and can not so I need someone to explain where I am going wrong.
It is a Sunday and I am trying to do extra work and have no notes to cover this exactly
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Student_Array
{
class Program
{
struct Student
{
public string Name;
}
static void Main(string[] args)
{
int numberOfStudents;
Student[] names;
string input;
Console.WriteLine("How many students are there?");
input = Console.ReadLine();
numberOfStudents = int.Parse(input);
names = new Student[numberOfStudents];
for (int i = 0; i < names.Length; i++)
{
Student s;
Console.WriteLine("Please enter student {0}'s name", (i + 1));
s.Name = Console.ReadLine();
names[i] = s;
}
***Array.Sort<Student>(names);***
for (int i = 0; i < names.Length; i++)
{
Console.WriteLine(names[i].Name);
}
}
}
}

This shall do the trick
Array.Sort(names, (x,y) => String.Compare(x.Name, y.Name));

Your issue here might be that you are confusing the notions of students and names. By defining the Student struct, you are creating an entity that can represent more than a mere name. You could, for example, extend it to include Age, Hometown, and so forth. (For this reason, it might be more meaningful to name your array students rather than names.)
struct Student
{
public string Name;
public int Age;
public string Hometown;
}
Given the possibility of multiple fields, the Array.Sort method needs to know what you want to sort your list upon. Do you want students ordered by name, by age, or by hometown?
Per the MSDN documentation on Array.Sort<T>:
Sorts the elements in an entire Array using the IComparable<T> generic interface implementation of each element of the Array.
This means that the type you are attempting to sort – in your case, Student – must implement the IComparable<T> interface, in order for the Array.Sort implementation to know how it should compare two Student instances. If you're convinced that students will always be sorted by name, you could implement it like so:
struct Student : IComparable<Student>
{
public string Name;
public int Age;
public string Hometown;
public int CompareTo(Student other)
{
return String.Compare(this.Name, other.Name);
}
}
Alternatively, you could provide a function that extracts the sort key to the sort method itself. The easiest way of achieving this is through the LINQ OrderBy method:
names = names.OrderBy(s => s.Name).ToArray();

You can either use Sort as is if you extend Student to implement IComparable;
struct Student : IComparable<Student>
{
public string Name;
public int CompareTo(Student other)
{
return String.Compare(Name, other.Name,
StringComparison.CurrentCultureIgnoreCase);
}
}
...or you can pass a compare lambda into Sort...
Array.Sort<Student>(names, (x, y) => String.Compare(x.Name, y.Name,
StringComparison.CurrentCultureIgnoreCase));
...or as a third option just create a new, sorted, array;
var newArray = names.OrderBy(x => x.Name.ToLower()).ToArray();

You can use this as well, instead of using Array.Sort.
names = names.OrderBy(p => p.Name).ToArray();

Create a comparer class
class StudentComparer : IComparer<Student>
{
public int Compare(Student a, Student b)
{
return a.Name.CompareTo(b.Name);
}
}
Sort:
Array.Sort(students,new StudentComparer());

To sort by the name property of your Student objects in your Student array, you can use
Array.Sort(names, (s1, s2) => String.Compare(s1.Name, s2.Name));
which will sort your array in place, or with System.Linq:
names = names.OrderBy(s => s.Name).ToArray();
which can return the sorted IEnumerable as an array (.ToArray()) or a list (.ToList().)
Remember to sort case-insensitive if it matters, as pointed out in another answer, which can be done in String.Compare like so:
String.Compare(s1.Name, s2.Name, StringComparison.CurrentCultureIgnoreCase)

you can find one of the basics algorithms here : Simple bubble sort c#
you have to do some modifications , that example is for int, for string you must compare the names.
you can find better algorithms for sorting. for now bubble sort is ok for you.

Related

List with int array - accessing the array

I have a class (students) with say 2 strings and an int array
A second class then does this:
List<student> myS = new List<student>();
All of this works correctly and I have a list containing multiple students. I am however having difficulty accessing the values within the int[].
So, my student list is populated from a database and into a list.
I then have a generic class which has a parameter List which I then want as a data table. The generic class will be called for the student class, subjects class and other classes - some of which may contain arrays and some which do not.
If I debug and step through, I get the following:
(() myS.stu[6].termMark[1] and the value is 50. However if I enter int d =stu[6].termMark[1] the error is T does not contain a definition for termMark and no extension method 'termMark' accepting a first argument of type T could be found.
int d = myS[0][1] returns the error
cannot apply indexing with [] to an expression of type 'T'
. I have tried various things like creating a separate list and adding it to myS. Nothing works.
Thanks in advance for the help.
I am fairly new to this and probably missing the obvious...
You must read about Generic Constraints
You cannot do much with an argument of type T.
If your function accepts arguments of type student , add a constraint like this
private static void NewMethod<T>(List<T> myS) where T : student
{
int d = myS[0].IntArray[1];
}
The following is not related your problem...
If you add an indexer to your class you can make it a little shorter
public class student
{
public int[] IntArray;
public int this[int x]
{
get
{
return IntArray[x];
}
}
}
private static void NewMethod<T>(List<T> myS) where T : student
{
int d = myS[0][3];
}
Perhaps the type T does not hold any definition for indexers. But, your field (int[]) does. So, instead of calling the indexer upon your object (student) call it on the field of it. So, for this answer I would assume that your object is declared as class like this
public class student {
public string S { get; set; }
public string s { get; set; }
public int[] integers { get; set; }
}
Now, you can indeed call the indexers on the integers field but not on the student object itself (it does not have any indexing mechanism). Such as,
int d = myS[0].integers[1]; // <-- your code should be
The above code (if compiled) would give you the element at the index 1 (2nd element) of the first object in the list. You were instead calling the element at index 1 of the student (which does not have indexers?).

Sort ArrayList with custom comparison

I am trying to sort an ArrayList using c#. When the ArrayList contains comparable objects, it is possible to sort with using list.Sort() but I need to sort an ArrayList which contains non-comparable objects. For example, let's say the object is Ring and it has an attribute property Price. Then I need to sort the ArrayList to the price order. If is is possible to select ascending or descending that will more helpful. Thank You!
Blockquote
arrAtdMon = **(ArrayList)**hashTb[unixMon];
if (arrAtdMon != null)
monCount = arrAtdMon.Count;
int[] arrayMax = { monCount, tueCount, wedCount, thuCount, friCount };
int maxValue = arrayMax.Max();
KidAttendance valMon = null;
string monTagName = string.Empty;
Blockquote
above array list is to be sorted it self.
You can do this by implementing IComparer interface:-
public class Ring : IComparer
{
public decimal Price { get; set; }
public int Compare(object x, object y)
{
return ((Ring)x).Price.CompareTo(((Ring)y).Price);
}
}
Working Fiddle.
First, you really should be using the List<T> class, not ArrayList. Doing so wouldn't solve your problem, but it would make the code less fragile and more easy to maintain.
As for the specific question, you want to do something like this…
Assume:
class Ring { public decimal Price { get; set; } }
Then:
ArrayList list = ...; // Initialized as some collection of Ring instances
list.Sort(Comparer.Create((r1, r2) => r1.Price.CompareTo(r2.Price)));
This creates a new Comparer instance using the Comparison<T> of (r1, r2) => r1.Price.CompareTo(r2.Price). That is, for each pair of objects being compared, compare the price of the first with the price of the second.
Assuming that these objects share a base class or an interface with the price property you should be able to do something like this:
// Base class with price property, could also be an shared interface
public abstract class Product
{
public decimal Price{get;set;}
}
public class Ring : Product
{
}
public class Bag : Product
{
}
// Some test data
var myUnsortedArray = new Product[]{new Ring{Price = 1.2m}, new Bag{Price=2.5m}};
// Easy sort with LINQ
var sortedProducts = myUnsortedArray.OrderBy(p => p.Price).ToArray();
var sortedProductsDescending = myUnsortedArray.OrderByDescending(p => p.Price).ToArray();
UPDATE
I just realised that the question is about ArrayLists and have the changed solution below:
// Some test data
var myUnsortedArrayList = new ArrayList{new Ring{Price = 1.2m}, new Bag{Price=2.5m}};
// Easy sort with LINQ
var sortedProducts = myUnsortedArrayList.OfType<Product>().OrderBy(p => p.Price).ToArray();
var sortedProductsDescending = myUnsortedArrayList.OfType<Product>().OrderByDescending(p => p.Price).ToArray();
To sort an set of objects, the object needs to be Comparable and you can set up the comparison you'd like in the CompareTo() method:
IComparable information here

How to search an element of an array and display

I need to display the grade each student has by asking for it's number. The grade each student has is tied with each student, can be the array place of each. The Student number is what is prompted to ask the search in the array. Could it possibly be done in a short Two liner?
using System;
using System.Text;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
string[] studentName = {"Bob","Marie","Nathan","Lois","Sam"};
string[] studentsNumber = {"040707701","040707702","040707703","040707704","040707705"};
string[] studentGrade = {"A","B","C","D","F"};
string studentsNumber = "";
Console.WriteLine("What is your student number");
Console.ReadLine(studentsNumber.ToString());
for(int index = 0, studentNumber[studentNumber - 1], index++)
{
Console.WriteLine(studentsNumber[index]);
onsole.WriteLine(studentName[],studentGrade[] {0} {1});
}
}
}
}
Since this is homework, I'm not going to give you the answer outright but give you a hint instead.
Once you have the student number, loop through the array of student numbers. Once you find the index of the matching number...you can use that to retrieve the grade.
Keep in mind, though, that arrays aren't the right way to solve this problem at all. You'd be much better off creating a class for student that included name, number, and grade. You could then create instances of the class and add those instances to a List that you could then iterate through.
Would be much better to have an object:
public class StudentInfo
{
public string Name {get; set;}
public string Grade {get; set;}
public int Number {get; set;}
}
And then have a List<StudentInfo>.
By doing it this way your data will be tight together. Otherwise you might end up in a situation where you have different number of items in each array and you wouldn-t know which one is which.
Hope it helps.
eek!
Why not use an anonymous class with a bit of linq?
var students = new[]
{
new { Name = "Bob", Number = "040707701", Grade = "A" },
...
};
var grade = students.Where(s => s.Number == "040707701").Select(s => s.Grade);

C# - sorting Dictionary

I have a Dictionary and I want to sort it by Person, could anyone write me how to do it? Yeah, I tried to find it in the internet, but without success :((
Class subject has 3 parametres - name (string), family_name (string), age (int).
And I want to sort it by for example family_name, if same then by age and finally by name (if also age is same) - could anyone write me the code how to do it?? Thanks a lot for your help ;-)
There are SortedDictionary and SortedList you can use; you'd want to make an IComparer for Person as well. See this for a discussion of their differences: http://msdn.microsoft.com/en-us/library/5z658b67(VS.80).aspx
The Dictionary class can't be sorted due to the way it stores values, but you can easily get a sorted collection of the values that you have in your dictionary using LINQ.
var sorted = dictionary.Values.OrderBy(s => s.name)
.ThenBy(s => s.family_name)
.ThenBy(s => s.age);
Dictionary is structure without order, so you cannot sort it - you can sort ordered structures like list
You can use SortedList or SortedDictionary, both of which sort by the key.
Since the key is a class you created, you can pass an IEqualityComparer into the constructor to control how it gets sorted.
Define a Person and a Comparer class :
public class Person
{
public string Name { get; set; }
public string FamilyName { get; set; }
public int Age { get; set; }
}
public class PersonComparer : IComparer<KeyValuePair<string, Person>>
{
public int Compare(KeyValuePair<string, Person> x, KeyValuePair<string, Person> y)
{
var result = x.Value.FamilyName.CompareTo(y.Value.FamilyName);
if(result != 0)
return result;
return x.Value.Age.CompareTo(y.Value.Age);
}
}
and use these classes lie this :
var myDictionary = new Dictionary<string, Person>();
//fill your dictionary
var list = myDictionary.ToList();
list.Sort(new PersonComparer());
this is a simple and working solution.

sorting enum for UI purpose

Say we have a UI and in this UI we have a dropdown. This dropdown is filled with the translated values of an enum.
Bow, we have the possibility to sort by the int-value of the enum, by the name of the enum, and by the translated name of the enum.
But what if we want a different sorting than the 3 mentioned above. how to handle such a requirement?
Implement your own IComparer:
using System;
using System.Collections.Generic;
namespace test {
class Program {
enum X {
one,
two,
three,
four
}
class XCompare : IComparer<X> {
public int Compare(X x, X y) {
// TBA: your criteria here
return x.ToString().Length - y.ToString().Length;
}
}
static void Main(string[] args) {
List<X> xs = new List<X>((X[])Enum.GetValues(typeof(X)));
xs.Sort(new XCompare());
foreach (X x in xs) {
Console.WriteLine(x);
}
}
}
}
You can use the Linq extension OrderBy, and perform whatever comparison magic you want:
// order by the length of the value
SomeEnum[] values = (SomeEnum[])Enum.GetValues(typeof(SomeEnum));
IEnumerable<SomeEnum> sorted = values.OrderBy(v => v.ToString().Length);
Then wrap the different sorting alternatives into methods, and invoke the right one based on user preferences/input.
IEnumerable<T>.OrderBy(Func<T, TKey>, IComparer<TKey>)
Sort FileSystemRights enum using Linq and bind to WinForms comboBox:
comboBox1.DataSource = ((FileSystemRights[])Enum.GetValues(typeof(FileSystemRights))).
OrderBy(p => p.ToString()).ToArray();
Perhapse you could create an extension method for the Enum class, like this:
... first the declaration...
public enum MyValues { adam, bertil, caesar };
...then in a method...
MyValues values = MyValues.adam;
string[] forDatabinding = values.SpecialSort("someOptions");
...The extension method...
public static class Utils
{
public static string[] SpecialSort(this MyValues theEnum, string someOptions)
{
//sorting code here;
}
}
And you could add different parameters to the extension metod for different sort options etc.

Categories