List<> own comparer - c#

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();
}
}

Related

Dynamic LINQ Method to return List of different Items from two lists

I want to write dynamic LINQ function to return the different between two lists but in abstraction way to make this function take any two lists of the same type and return the items that is the first list but not in the second one
I write some thing like the below and it is working fine but as I mention above I need it in abstraction way
List<Employee> a = List of Items;
List<Employee> b = List of Items;
var finalCountries = a.Where(u => !b.Any(u2 => u2.ISOA2 == u.ISOA2)).ToList();
I read about dynamic LINQ expression but it is complex and I have no luck to find what I am looking to
if there are any way to write the above where statement as string and execute it?
You can use Enumerable.Except like this
List<Employee> a;
List<Employee> b;
var finalCountries = a.Except(b).ToList();
If you need to compare your Employees by some field and this is not implemented by Employee you can use a custom comparer. For example this one. When your code can look like:
var comparer = new LambdaComparer<Employee>((emp1,emp2)=>emp1.ISOA2 == emp2.ISOA2);
var finalCountries = a.Except(b,comparer).ToList();
LambdaComparer code for convenience:
class LambdaComparer<T> : IEqualityComparer<T>
{
readonly Func<T, T, bool> _lambdaComparer;
readonly Func<T, int> _lambdaHash;
public LambdaComparer(Func<T, T, bool> lambdaComparer) :
this(lambdaComparer, o => 0){}
public LambdaComparer(Func<T, T, bool> lambdaComparer, Func<T, int> lambdaHash)
{
_lambdaComparer = lambdaComparer ?? throw new ArgumentNullException(nameof(lambdaComparer));
_lambdaHash = lambdaHash ?? throw new ArgumentNullException(nameof(lambdaHash));
}
public bool Equals(T x, T y) => _lambdaComparer(x, y);
public int GetHashCode(T obj) => _lambdaHash(obj);
}
update:
To make your method generic you can implement IEquatable interface in each of your entity types and use Except overload without parameters.

Can a class inherit from a collection and still efficiently interact with LINQ?

I have a C# class that inherits from a collection. I make heavy use of LINQ, so calls to my class methods are intermingled with LINQ calls. Unfortunately this means that I frequently cast the IEnumerable<> returned by LINQ back into my class type in the middle of a pipeline. This results in excess code, and it is computationally inefficient.
Another solution is to implement the class methods as extension methods. This is more efficient, but in this case I will end up having to reproduce functionality that I could inherit from a collection.
Is there a way to inherit from collections, but still efficiently interact with LINQ?
The following program contains two queries. The first query calls a method from a derived class, but it also requires an O(n) call to ToMyList(). The second query is more efficient, but it is not making use of a derived class.
using System.Collections.Generic;
using System.Linq;
namespace StackOverflow
{
// A custom list that can multiply every element by a constant integer.
public class MyList : List<int>
{
public MyList() : base() { }
public MyList(IEnumerable<int> items) : base(items) { }
public MyList Multiply(int n)
{
for(int i = 0; i < Count; ++i)
this[i] *= n;
return this;
}
}
public static class Extensions
{
// Convert from IEnumerable<int> to MyList.
public static MyList ToMyList(this IEnumerable<int> items)
{
return new MyList(items);
}
// An extension version of the multipy method.
public static IEnumerable<int> Multiply(this IEnumerable<int> items, int n)
{
foreach (var item in items)
yield return n * item;
}
}
class Program
{
static void Main(string[] args)
{
// Create a large list.
var myList = new MyList();
for (int i = 0; i < 1000000; ++i) myList.Add(i);
// Call the MyList.Multiply method.
var query1 = myList.Skip(100).ToMyList().Multiply(5);
// Call the extension version of the Multiply method.
var query2 = myList.Skip(100).Multiply(5);
}
}
}
The short answer is no. On the one hand, a list (and any derivative) is necessarily managing its own copy of the data. On the other hand, Linq transforms data without storing it. So if you perform a Linq operation and you want it back in the MyList instance then you necessarily have to incur the O(N) cost of storing it.
What you could do, depending on your intended use, is modify MyList so that instead of deriving from list, it holds an enumerable, and stores transformations on that enumerable. This would allow the following:
public class MyNonList : IEnumerable<int>
{
IEnumerable<int> _inner;
public MyNonList(IEnumerable<int> inner)
{
_inner = inner;
}
public MyNonList Multiply(int n)
{
return new MyNonList(_inner.Select(i => i * n));
}
public IEnumerator<int> GetEnumerator() => _inner.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_inner).GetEnumerator();
}
public static class Extensions
{
// Convert from IEnumerable<int> to MyList.
public static MyNonList ToMyNonList(this IEnumerable<int> items)
{
return new MyNonList(items);
}
}
class Program
{
static void Main(string[] args)
{
// Create a large list.
var list = new List<int>();
for (int i = 0; i < 1000000; ++i)
list.Add(i);
var myList = new MyNonList(list);
// Call the MyList.Multiply method.
MyNonList myList2 = myList.Skip(100).ToMyNonList().Multiply(5);
}
}
But in this trivial example, this really offers very little over just implementing the static extension method. (Which, by the way is a perfectly reasonable thing to do).
You could also split MyList out to two separate classes: one that derives from List, and actually holds data; and a second in the manner here that contains the transformation methods of interest, finishing with its own ToMyList implementation that finally realises and stores the enumerable data.

Iterate/enumerate over part of a list?

Is there a way to remember the position of an enumerator?
I want to remember the position of an enumerate, so that I can reset it to a position before the current. I don't want to go back to the beginning so .reset() doesn't help.
Btw, is it possible to let the enumerator start eg at the 2. position?
List<string> list = new List<string>(new string[] { "a", "b", "c" });
IEnumerator<string> i = list.GetEnumerator();
i.MoveNext(); richTextBoxOutput.AppendText(i.Current);
IEnumerator<string> t = i; // how do I make a real copy i?
i.MoveNext(); richTextBoxOutput.AppendText(i.Current);
i = t;
i.MoveNext(); richTextBoxOutput.AppendText(i.Current);
As you already have a List<> why don't you maintain an indexer/counter then use the IEnumerable Skip() extension method (and possibly combine that with Take() followed by ForEach()).
Some possibly useful further info:
MSDN: Return Or Skip Elements in a Sequence
Stack Overflow: LINQ with Skip and Take
Is there a way to remember the position of an enumerator?
Sometimes. It depends on how the enumerator is implemented.
In this case the enumerator is implemented as a mutable struct, which was a performance optimisation that people more often run into when it produces this "freeze position" behaviour in situations where they don't want it. (If you're ever writing a generic class that wraps an implementation of IEnumerable<T> then either hold that reference as the interface type rather than the type itself, or don't have it readonly even if it seems like it should be, if you do you can end up with such a struct enumerator permanently frozen).
Just change your code so that instead of:
IEnumerator<string> i = list.GetEnumerator();
…
IEnumerator<string> t = i;
You have either:
List<string>.Enumerator i = list.GetEnumerator();
…
List<string>.Enumerator t = i;
Or simply:
var i = list.GetEnumerator();
…
var t = i;
Now you have i and t defined in terms of this struct and copying from one to the other copies the struct rather than just the reference to the boxed struct.
This will not work with all enumerators, and for that matter it isn't the best way to deliberately make it available when writing your own enumerator (if you needed to do so you'd be better adding some sort of Clone() or Snapshot() method to an enumerator that was a class rather than a struct), but it will work with List<T>.
A more flexible solution that doesn't depend on such a quirk of implementation would be:
public class SnapshotableListEnumerator<T> : IEnumerator<T>
{
private readonly IList<T> _list;
private int _idx;
private SnapshotableListEnumerator(IList<T> list, int idx)
{
_list = list;
_idx = idx;
}
public SnapshotableListEnumerator(IList<T> list)
: this(list, -1)
{
}
public bool MoveNext()
{
// Note that this enumerator doesn't complain about the list
// changing during enumeration, but we do want to check that
// a change doesn't push us past the end of the list, rather
// than caching the size.
if(_idx >= _list.Count)
return false;
++_idx;
return true;
}
public void Reset()
{
_idx = -1;
}
public T Current
{
get
{
if(_idx < 0 || _idx >= _list.Count)
throw new InvalidOperationException();
return _list[_idx];
}
}
object IEnumerator.Current
{
get { return Current; }
}
public void Dispose()
{
}
public SnapshotableListEnumerator<T> Snapshot()
{
return new SnapshotableListEnumerator<T>(_list, _idx);
}
}
public static class SnapshotableListEnumeratorHelper
{
public static SnapshotableListEnumerator<T> GetSnapshotableEnumerator<T>(this IList<T> list)
{
return new SnapshotableListEnumerator<T>(list);
}
}
Now you can call GetSnapshotableEnumerator() on any implementation of IList<T> and use its Snapshot() method whenever you want a copy of the position within the enumeration.
Do you definitely need an IEnumerator instance? Why not enumerate using the index and store that in your own variable?
var list = new List<string>(new { "a", "b", "c" });
var pos = 2; // this is the position
richTextBoxOutput.AppendText(list[pos]);
You can reset at any time with:
pos = (desired position);

Unified way to access arrays with different types

Supposing I have the following classes:
class Master {
int x;
int y;
public int X { get { return x; } set { x = value; } }
public int Y { get { return y; } set { y = value; } }
}
class Sub1:Master {
int z;
public int Z { get { return z; } set { z = value; } }
}
class Sub2:Master {
int w;
public int W { get { return w; } set { w = value; } }
}
class Sub3:Master {
int t;
public int T { get { return t; } set { t = value; } }
}
Then I have defined three different arrays, one for each Sub* type:
List<Sub1> array1;
List<Sub2> array2;
List<Sub3> array3;
And finally I need a way to access all instances in a unified way. The idea was to use a new array List<T>[] array4 = new[] {array1, array2, array3}; and use an int as index, so I don't have to write three times the common operations for properties X and Y.
However, I can't do it in this way because the three arrays have different type. What can I use?
They share a base type so you can create a List<Master> to hold instances of all three types.
Ultimately, all objects share the same base type object so it always possible to have a List<object>, but in this case they share a base type higher in the hierarchy so you can use Master.
To create a list for all the instances you can do something like this:
var all = new List<Master>(array1.Count + array2.Count + array3.Count);
all.AddRange(array1);
all.AddRange(array2);
all.AddRange(array3);
First you create a new list and since you already know what the expected capacity should be you use the constructor overload that accepts an int capacity. This way the list does not have to be resized when you add the other collections, which leads to more efficient code.
As a side note and I know this is probably only sample code but nonetheless you should name your variables according to what they represent, so naming something like array* should be reserved for when they really represent arrays.
List implements the non-generic interfaces ICollection, IEnumerable and IList, so you can create a new array of IList[] array4 = { array1, array2, array3 };
Or, while adding elements at your Lists you could add them (also) to another list of type Master, like this
List<Sub1> array1 = new List<Sub1>();
List<Sub2> array2 = new List<Sub2>();
List<Sub3> array3 = new List<Sub3>();
List<Master> array4 = new List<Master>();
...
public void AddSub1(Sub1 sub)
{
array1.Add(sub);
array4.Add(sub);
}
public void AddSub2(Sub2 sub)
{
array2.Add(sub);
array4.Add(sub);
}
public void AddSub3(Sub3 sub)
{
array3.Add(sub);
array4.Add(sub);
}
This way, you can iterate over all elements of array4:
foreach(Master master in array4)
{
master.DoSomething();
}
You can actually make this work by using the fact that IEnumerable<T> is declared as IEnumerable<out T>, and that Enumerable.ElementAt<T> is optimized for the runtime type of the IEnumerable<T> implementing IList<T>. That lets you do this:
var x = new IEnumerable<Master>[] {array1, array2, array3};
x[0].ElementAt(4);
While still getting constant-time access to the individual elements of the lists. It feels a little clunky, but should still work.
If it fits the work being done, a better option in my opinion would be to create a generic method, and call the generic method on each of your lists:
private void MainMethod()
{
List<Sub1> array1 = new List<Sub1>();
List<Sub2> array2 = new List<Sub2>();
List<Sub3> array3 = new List<Sub3>();
DoOperation(array1);
DoOperation(array2);
DoOperation(array3);
}
private void DoOperation<T>(List<T> list) where T: Master
{
// do work here
list[0].X = 0;
}

.NET IComparable: how to implement

I have a collection of objects I need to order but not sure how.
There is a string property called, say Prop1, that I want to sort by. And I want to sort based on a List of strings which contain all possible values of Prop1.
List<string> precedence = new List<string>() { "firstPrecedence", "secondPrecedence" ....
How would I implement my CompareTo(object obj) method?
I'm trying with this but don't really know what i'm doing!
public int CompareTo(object obj)
{
List<string> precedence = new List<string>() { "firstPrecedence", "secondPrecedence", "thirdPrecedence" };
Filter filterOther = obj as Filter;
foreach (var item in precedence)
{
return String.Compare(filterOther.FilterValue, item);
}
return 0;
}
Well, if your precedence list is known at compile time and you can use it, then you can compare the indexes of the values you are sorting:
private static List<string> Precedence = new List<string>() { "item1", "item2", "item3" }; // etc
public int CompareTo(object obj)
{
Filter item = obj as Filter; // Assume not null.
int otherIndex = Precedence.IndexOf(item.FilterValue);
int thisIndex = Precedence.IndexOf(this.FilterValue); // Assume 'this' is a Filter
// This may need to be otherIndex.CompareTo(thisIndex) depending on the direction of sort you want.
return thisIndex.CompareTo(otherIndex);
}
If the FilterValue value is not in the list, IndexOf will return -1, which will still work in the sorting implementation here, but may sort at the top or bottom of the list... I can never remember which!
Note that the CompareTo method returns either 0, something less than 0, or something greater than 0. Usually, -1, 0, and 1.
Also, there is a generic IComparable<> which will allow you to achieve this in a more strongly-typed way:
public class Filter : IComparable<Filter>
{
}
And I'm sure some clever person will give you a solution in LINQ...
try this (assuming you have a List<Filter> )
filterObjectList.Sort((f1,f2) => precedence.IndexOf(f1.FilterValue).CompareTo(precedence.IndexOf(f2.FilterValue));
Using LINQ:
precedence.SelectMany(p => objs.Where(o => o.Prop1 == p));
OR
objs.Select(s => new { Index = precedence.IndexOf(s.Prop1), Obj = s })
.OrderBy(a => a.Index).Select(a => a.Obj);
Create a new class of your object that you want to sort:
public class MySortableObject: IComparable {
private string str;
public MySortableObject(string _str) {
this.str = _str;
}
int IComparable.CompareTo(object obj) {
MySortableObject comparedObj = (MySortableObject) obj;
// Implement here the code that will compare the current object (this) and the compared object (comparedObj)
// It must return -1 if this instance precedes comparedObj in the sort order
// It must return 1 if this instance follows comparedObj in the sort order
// It must return 0 if this instance occurs in the same position in the sort order as comparedObj
// Use for example String.CompareTo() method to implement this, or your own code (with if(), switch()... whatever you need)
}
}

Categories

Resources