ArrayList object sorting - c#

I have to sort ArrayList which consists of objects. Object: ID, Quantity. The ArrayList should be sorted by ID. How to implement this?
ItemIdQuantity = new ItemIdQuantity (ID, Quantity);
ItemIdQuantity.Sort(); // where must be sorting by ID

public class IdComparer : IComparer {
int IComparer.Compare(object x, object y) {
return Compare((ItemIdQuantity)x, (ItemIdQuantity)y);
}
public int Compare(ItemIdQuantity x, ItemIdQuantity y) {
return x.ID - y.ID;
}
}
arrayList.Sort(new IdComparer());

Assuming that this is Java:
If the ItemIdQuantity class implements Comparable based on the ID field, use Collections.sort() with the list as single parameter.
Otherwise, implement a Comparator that compares the objects using their ID, and use it as second paramter to Collections.sort().

Related

How come SortedSet gives unique output without using IEqualitycomparer

At high level getting unique values for reference types requires implementing IEqualityComparer with HashSet but with SortedSet which is HashSet as well it does not seem to be required.
Here is an example. Lets say we have Employee class and EmployeeComparer classes below -
public class Employee
{
public string Name { get; set; }
public int Age { get; set; }
}
public class EmployeeComparer : IEqualityComparer<Employee>, IComparer<Employee>
{
public bool Equals(Employee x, Employee y)
{
return string.Equals(x.Name, y.Name);
}
public int GetHashCode(Employee obj)
{
return obj.Name.GetHashCode();
}
public int Compare(Employee x, Employee y)
{
return string.Compare(x.Name, y.Name);
}
}
If I have to use HashSet to get unique Employees based on name it works only if I have EmployeeComparer implementing IEqualityComparer but if I use SortedSet it gives me unique values even if the class EmployeeComparer does not implement IEqualityComparer and just the IComparer. What happens to the requirement of providing GetHashCode() and Equals() method for uniqueness here?
An IComparer<T> is fully sufficient for determining whether two objects are semantically equal.
If ICompararer<T>.Compare() returns 0, then the objects are considered to be equal. If it returns a nonzero value, then they are considered to be nonequal. Since the SortedSet<T> is supposed to put the values in sorted order, it needs a comparison function, but it doesn't need an equality function on top of that.

Sorting C# List based on its element

I have the C# class as follows :
public class ClassInfo {
public string ClassName;
public int BlocksCovered;
public int BlocksNotCovered;
public ClassInfo() {}
public ClassInfo(string ClassName, int BlocksCovered, int BlocksNotCovered)
{
this.ClassName = ClassName;
this.BlocksCovered = BlocksCovered;
this.BlocksNotCovered = BlocksNotCovered;
}
}
And I have C# List of ClassInfo() as follows
List<ClassInfo> ClassInfoList;
How can I sort ClassInfoList based on BlocksCovered?
myList.Sort((x,y) => x.BlocksCovered.CompareTo(y.BlocksCovered)
This returns a List<ClassInfo> ordered by BlocksCovered:
var results = ClassInfoList.OrderBy( x=>x.BlocksCovered).ToList();
Note that you should really make BlocksCovered a property, right now you have public fields.
If you have a reference to the List<T> object, use the Sort() method provided by List<T> as follows.
ClassInfoList.Sort((x, y) => x.BlocksCovered.CompareTo(y.BlocksCovered));
If you use the OrderBy() Linq extension method, your list will be treated as an enumerator, meaning it will be redundantly converted to a List<T>, sorted and then returned as enumerator which needs to be converted to a List<T> again.
I'd use Linq, for example:
ClassInfoList.OrderBy(c => c.ClassName);

List<T>.Distinct() in C# - multiple criteria for EqualityComparer?

I have a collection of objects which have several properties in each of them. I often need to get a list of distinct values for many properties in this collection. If I implement IEqualityComparer on this type , it gives me one single criteria for getting the distinct objects in the collection. How do I get to be able to call Distinct on multiple criteria for this collection ?
For example ,
class Product {
string name ;
string code ;
string supplier ;
//etc
}
Imagine a list of such product objects.
Sometimes , I want to get list of distinct names in the list , and at some oter time , a list of distinct supplier . etc.
If I call Distinct on a list of these products , based on the way IEqualityComparer is implemented , it will always use the same criteria , which is not going to serve my purpose.
Simply provide different IEqualityComparer implementations for different calls to Distinct. Note the difference between IEquatable and IEqualityComparer - usually a type shouldn't implement IEqualityComparer for itself (so Product wouldn't implement IEqualityComparer<Product>). You'd have different implementations, such as ProductNameComparer, ProductCodeComparer etc.
However, another alternative is to use DistinctBy in MoreLINQ
var distinctProducts = products.DistinctBy(p => p.name);
You can use the Distinct() overload that accepts an IEqualityComparer argument.
You could also create a comparer that accepts function arguments for the Equals and GetHashCode methods. Something like
class Foo
{
public string Name { get; set; }
public int Id { get; set; }
}
class FooComparer : IEqualityComparer<Foo>
{
public FooComparer(Func<Foo, Foo, bool> equalityComparer, Func<Foo, int> getHashCode)
{
EqualityComparer = equalityComparer;
HashCodeGenerator = getHashCode;
}
Func<Foo, Foo, bool> EqualityComparer;
Func<Foo, int> HashCodeGenerator;
public bool Equals(Foo x, Foo y)
{
return EqualityComparer(x, y);
}
public int GetHashCode(Foo obj)
{
return HashCodeGenerator(obj);
}
}
...
List<Foo> foos = new List<Foo>() { new Foo() { Name = "A", Id = 4 }, new Foo() { Name = "B", Id = 4 } };
var list1 = foos.Distinct(new FooComparer((x, y) => x.Id == y.Id, f => f.Id.GetHashCode()));

List<> own comparer

I have a List where element is:
struct element {
double priority;
int value;
}
How can I implement my own comparer which allow me sort List by priority ? I try with SortredList... but it don't allow douplicated keys :(
Big thanks for help!
Assuming C# 3 or later:
var sorted = MyList.OrderBy(e => e.priority);
You can perform an in-place sort by using the Sort overload that takes a Comparison<T> delegate:
yourList.Sort((x, y) => x.priority.CompareTo(y.priority));
For older versions of C# you'll need to swap out the lambda for old-school delegate syntax:
yourList.Sort(
delegate(element x, element y) { return x.priority.CompareTo(y.priority); });
If you can't rely on C# 3 extensions or Lambdas then you can have your struct implement the IComparable interface, like so:
struct element : IComparable
{
double priority;
int value;
public element(int val, double prio)
{
priority = prio;
value = val;
}
#region IComparable Members
public int CompareTo(object obj)
{
// throws exception if type is wrong
element other = (element)obj;
return priority.CompareTo(other.priority);
}
#endregion
}
There are also a typesafe version of this interface, but the principle is the same
After you have that interface implemented on your struct or class, calling the Sort method on List<> will "just work"
static void Main(string[] args)
{
Random r = new Random();
List<element> myList = new List<element>();
for (int i = 0; i < 10; i++)
myList.Add(new element(r.Next(), r.NextDouble()));
// List is now unsorted
myList.Sort();
// List is now sorted by priority
Console.ReadLine();
}
This depends on if you want to sort the list itself, or retrieve the values in sorted order (without changing the list).
To sort the list itself (supposing you have a List<element> called elements):
elements.Sort((x, y) => x.priority.CompareTo(y.priority));
// now elements is sorted
.NET 2.0 equivalent:
elements.Sort(
delegate(element x, element y) {
return x.priority.CompareTo(y.priority);
}
);
To get the values in sorted order:
var orderedElements = elements.OrderBy(x => x.priority);
// elements remains the same, but orderedElements will retrieve them in order
There's no LINQ equivalent in .NET 2.0, but you can write your own:
public static IEnumerable<T> OrderBy<T>(IEnumerable<T> source, Comparison<T> comparison) {
List<T> copy = new List<T>(source);
copy.Sort(comparison);
foreach (T item in copy)
yield return item;
}
Usage:
Comparison<element> compareByPriority = delegate(element x, element y) {
return x.priority.CompareTo(y.priority);
};
// unfortunately .NET 2.0 doesn't support extension methods, so this has to be
// expressed as a regular static method
IEnumerable<element> orderedElements = OrderBy(elements, compareByPriority);
If you want to sort the list itself without creating a new instance, you can implement
IComparer, then call List.Sort with an instance of your implementation
public class ElementComparer : IComparer<element>
{
public int Compare(element x, element y)
{
throw new NotImplementedException();
}
}

Selecting DataRows into new structures using LINQ. Calling Distinct() fails

Consider these two structures:
struct Task
{
public Int32 Id;
public String Name;
public List<Registration> Registrations;
}
struct Registration
{
public Int32 Id;
public Int32 TaskId;
public String Comment;
public Double Hours;
}
I am selecting a bunch of entries in a DataTable into new structures, like so:
var tasks = data.AsEnumerable().Select(t => new Task
{
Id = Convert.ToInt32(t["ProjectTaskId"]),
Name = Convert.ToString(t["ProjectTaskName"]),
Registrations = new List<Registration>()
});
But when I call Distinct() on the collection, it doesn't recognize objects with the same values (Id, Name, Registrations) as being equal.
But if I use an equality comparer; comparing the Id property on the objects, it's all fine and dandy...:
class TaskIdComparer : IEqualityComparer<Task>
{
public bool Equals(Task x, Task y)
{
return x.Id == y.Id;
}
public Int32 GetHashCode(Task t)
{
return t.Id.GetHashCode();
}
}
What am I missing here? Is Distinct() checking something else than the value of properties?
LINQ's Distinct method compares objects using the objects' Equals and GetHashCode implementations.
Therefore, if these methods are not overridden, it will compare by reference, not by value.
You need to use an EqualityComparer. (Or implement Equals and GetHashCode for the Task class)
my guess is that it's the list in there. Almost certainly, the two list objects are different, even if they contain the same info.

Categories

Resources