C# has no SortedList<T>? - c#

I'm trying to solve a problem in which it would be useful to have a data structure like
var list = new SortedList<int>();
list.Add(3); // list = { 3 }
list.Add(1); // list = { 1, 3 }
list.Add(2); // list = { 1, 2, 3 }
int median = list[list.Length / 2];
i.e.
O(n) insertion
O(1) lookup by index
but I can't see that such a thing exists? I see that there's some confusing SortedList<T,U> and then an interface SortedList, but neither of those are what I'm looking for.

The sorted list in the .NET framework is an associative list (that is it is for key/value pairs). You can use a regular List<T> if you use its binary search functionality, which works if you keep the list sorted at all times. You can encapsulate it in an extension method:
static class SortedListExtensions {
public static void SortedAdd<T>(this List<T> list, T value) {
int insertIndex = list.BinarySearch(value);
if (value < 0) {
value = ~value;
}
list.Insert(insertIndex, value);
}
//Added bonus: a faster Contains method
public static bool SortedContains<T>(this List<T> list, T value) {
return list.BinarySearch(value) >= 0;
}
}
List<int> values = new List<int>();
values.SortedAdd(3);
values.SortedAdd(1);
values.SortedAdd(2);

Related

Is there a String.Join()-like method for arrays of any object?

Is there a method that inserts an object between each object in an array?
For example, given an array of non-zero integers, is there a way to insert 0 in between each element? E.g. change [1, 2, 3] to [1, 0, 2, 0, 3]?
Specifically, I am looking to do something declarative like String.Join(0, [1, 2, 3]), but with arbitrary arrays (not just char arrays). A non-declarative way would be something like this:
public static IList<T> InterleaveWith<T>( this IList<T> #this, T divider ) {
IList<T> joined = new List<T>( #this.Count * 2 );
foreach( T item in #this ) {
joined.Add( item );
joined.Add( divider );
}
joined.RemoveAt( joined.Count - 1 );
return joined;
}
There is no built-in method, but you can do it easily with yield return:
static IEnumerable<T> Join<T>(T separator, IEnumerable<T> items) {
bool first = true;
foreach (var item in items) {
if (!first) {
yield return separator;
} else {
first = false;
}
yield return item;
}
}
Demo.
The approach that uses as much built-in functionality as available would be to use SelectMany:
static IEnumerable<T> Join<T>(this IEnumerable<T> items, T separator) =>
items.SelectMany((item, index) =>
index == 0 ? new[] { item } : new[] { separator, item });
Realistically though, I'd probably go for a custom implementation similar to what #dasblinkenlight wrote up.

Generate permutations using polymorphic method

The instructions :
Please write a piece of code that takes as an input a list in which
each element is another list containing an unknown type and which
returns a list of all possible lists that can be obtained by taking
one element from each of the input lists.
For example:
[[1, 2], [3, 4]], should return: [[1, 3], [1, 4], [2, 3], [2, 4]].
[['1'], ['2'], ['3', '4' ]], should return [['1', '2', '3'], ['1',
'2', '4']].
My code:
public static void Main(string[] args)
{
//Create a list of lists of objects.
var collections = new List<List<object>>();
collections.Add(new List<object> { 1, 5, 3 });
collections.Add(new List<object> { 7, 9 });
collections.Add(new List<object> { "a", "b" });
//Get all the possible permutations
var combinations = GetPermutations(collections);
//Loop through the results and display them in console
foreach (var result in combinations)
{
result.ForEach(item => Console.Write(item + " "));
Console.WriteLine();
}
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
private static List<List<object>> GetPermutations(List<List<object>> collections)
{
List<List<object>> permutations = new List<List<object>>();
//Check if the input list has any data, else return the empty list.
if (collections.Count <= 0)
return permutations;
//Add the values of the first set to the empty List<List<object>>
//permutations list
foreach (var value in collections[0])
permutations.Add(new List<object> { value });
/* Skip the first set of List<List<object>> collections as it was
* already added to the permutations list, and loop through the
* remaining sets. For each set, call the AppendValues function
* to append each value in the set to the permuations list.
* */
foreach (var set in collections.Skip(1))
permutations = AppendNewValues(permutations, set);
return permutations;
}
private static List<List<object>> AppendNewValues(List<List<object>> permutations, List<object> set)
{
//Loop through the values in the set and append them to each of the
//list of permutations calculated so far.
var newCombinations = from additional in set
from value in permutations
select new List<object>(value) { additional };
return newCombinations.ToList();
}
How could I make it work with polymorphic method that returns a generic list?
Please write a piece of code that takes as an input a list in which each element is another list containing an unknown type and which returns a list of all possible lists that can be obtained by taking one element from each of the input lists.
I would have asked for clarification, something like "You mean a generic method then?"
In speaking of polymorphism, they were likely being able to write just one method and call it form any arbitrary type, something like:
public static IList<IList<T>> GetPermutations<T>(IList<IList<T>> inputLists) {
if (inputLists.Count < 2) {
// special case.
}
return _permutationHelper(0, inputLists);
}
private static IList<IList<T>> _permutationHelper<T>(int i, IList<IList<T>> inputLists) {
IList<IList<T>> returnValue = new List<IList<T>>();
if (i == inputLists.Count) {
returnValue.Add(new List<T>());
} else {
foreach (var t in inputLists[i]) {
foreach (var list in _permutationHelper(i + 1, inputLists)) {
list.Add(t);
returnValue.Add(list);
}
}
}
return returnValue;
}
It is true that your implementation would allow arbitrary types at run time, but it loses type safety. Given that it's an implementation in C#, type safety being a requirement is a safe guess - but it doesn't hurt to ask either.
Another thing of note - they could have just said they were looking for the Cartesian product of the given lists.
All I can think of is that they were not trying to mix different types in the lists(like you implemented), the types of all lists would be the same and they wanted you to write a Generic Class that would handle the problem for different types of lists, resulting in something like this:
static void Main(string[] args)
{
var intCollections = new List<List<int>>();
intCollections.Add(new List<int> { 1, 5, 3 });
intCollections.Add(new List<int> { 7, 9 });
var stringCollections = new List<List<String>>();
stringCollections.Add(new List<String> { "a", "b" });
stringCollections.Add(new List<String> { "c","d", "e" });
stringCollections.Add(new List<String> { "g", "f" });
//here you would have the "polymorphism", the same signature for different Lists types
var intCombinations = GetPermutations(intCollections);
var stringCombinations = GetPermutations(stringCollections);
foreach (var result in intCombinations)
{
result.ForEach(item => Console.Write(item + " "));
Console.WriteLine();
}
Console.WriteLine();
foreach (var result in stringCombinations)
{
result.ForEach(item => Console.Write(item + " "));
Console.WriteLine();
}
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
//This would be your generic implementation, basically changing from object to T and adding <T> after method
private static List<List<T>> GetPermutations<T>(List<List<T>> collections)
{
List<List<T>> permutations = new List<List<T>>();
//Check if the input list has any data, else return the empty list.
if (collections.Count <= 0)
return permutations;
//Add the values of the first set to the empty List<List<object>>
//permutations list
foreach (var value in collections[0])
permutations.Add(new List<T> { value });
/* Skip the first set of List<List<object>> collections as it was
* already added to the permutations list, and loop through the
* remaining sets. For each set, call the AppendValues function
* to append each value in the set to the permuations list.
* */
foreach (var set in collections.Skip(1))
permutations = AppendNewValues(permutations, set);
return permutations;
}
private static List<List<T>> AppendNewValues<T>(List<List<T>> permutations, List<T> set)
{
//Loop through the values in the set and append them to each of the
//list of permutations calculated so far.
var newCombinations = from additional in set
from value in permutations
select new List<T>(value) { additional };
return newCombinations.ToList();
}
This generic implementation, comparing to yours, have the advantage of type Safety, it makes sure you will not mix different object types.

Using C# Dictionary to parse log file

I am trying to parse a rather long log file and creating a better more manageable listing of issues.
I am able to read and parse out the individual log line by line, but what I need to do is display only unique entries, as some errors occur more often than others and are always recorded with identical text.
What I was going to try to do was create a Dictionary object to hold each unique entry and as I work through the log file, search the Dictionary object to see if the same values are already in there.
Here is a crude sample of the code I have (a work in progress, I hope I have all syntax right) that does not work. For some reason this script never sees any distinct entries (if statement never passes):
string[] rowdta = new string[4];
Dictionary<string[], int> dict = new Dictionary<string[], int>();
int ctr = -1;
if (linectr == 1)
{
ctr++;
dict.Add(rowdta, ctr);
}
else
{
foreach (KeyValuePair<string[], int> pair in dict)
{
if ((pair.Key[1] != rowdta[1]) || (pair.Key[2] != rowdta[2])| (pair.Key[3] != rowdta[3]))
{
ctr++;
dict.Add(rowdta, ctr);
}
}
}
Some sample data:
First line
rowdta[0]="ErrorType";
rowdta[1]="Undefined offset: 0";
rowdta[2]="/url/routesDisplay2.svc.php";
rowdta[3]="Line Number 5";
2nd line
rowdta[0]="ErrorType";
rowdta[1]="Undefined offset: 0";
rowdta[2]="/url/routesDisplay2.svc.php";
rowdta[3]="Line Number 5";
3rd line
rowdta[0]="ErrorType";
rowdta[1]="Undefined variable: fvmsg";
rowdta[2]="/url/processes.svc.php";
rowdta[3]="Line Number 787";
So, with this, the Dictionary will have 2 items in it, first line and 3rd line.
I have also tried this with the following which nalso does not find any variations in the log file text.
if (!dict.ContainsKey(rowdta)) {}
Can someone please help me get this syntax right? I am just a newbie at C# but this should be relatively straightforward. As always, I am thinking that this should be enough information to get the conversation started. If you want/need more detail, please let me know.
Either create a wrapper for your strings which implements IEquatable.
public class LogFileEntry :IEquatable<LogFileEntry>
{
private readonly string[] _rows;
public LogFileEntry(string[] rows)
{
_rows = rows;
}
public override int GetHashCode()
{
return
_rows[0].GetHashCode() << 3 |
_rows[2].GetHashCode() << 2 |
_rows[1].GetHashCode() << 1 |
_rows[0].GetHashCode();
}
#region Implementation of IEquatable<LogFileEntry>
public override bool Equals(Object obj)
{
if (obj == null)
return base.Equals(obj);
return Equals(obj as LogFileEntry);
}
public bool Equals(LogFileEntry other)
{
if(other == null)
return false;
return _rows.SequenceEqual(other._rows);
}
#endregion
}
Then use that in your dictionary:
var d = new Dictionary<LogFileEntry, int>();
var entry = new LogFileEntry(rows);
if( d.ContainsKey(entry) )
{
d[entry] ++;
}
else
{
d[entry] = 1;
}
Or create a custom comparer similar to that proposed by #dasblinkenlight and use as follows
public class LogFileEntry
{
}
public class LogFileEntryComparer : IEqualityComparer<LogFileEntry>{ ... }
var d = new Dictionary<LogFileEntry, int>(new LogFileEntryComparer());
var entry = new LogFileEntry(rows);
if( d.ContainsKey(entry) )
{
d[entry] ++;
}
else
{
d[entry] = 1;
}
The reason that you see the problem is that an array of strings cannot be used as a key in a dictionary without supplying a custom IEqualityComparer<string[]> or writing a wrapper around it.
EDIT Here is a quick and dirty implementation of a custom comparer:
private class ArrayEq<T> : IEqualityComparer<T[]> {
public bool Equals(T[] x, T[] y) {
return x.SequenceEqual(y);
}
public int GetHashCode(T[] obj) {
return obj.Sum(o => o.GetHashCode());
}
}
Here is how you can use it:
var dd = new Dictionary<string[], int>(new ArrayEq<string>());
dd[new[] { "a", "b" }] = 0;
dd[new[] { "a", "b" }]++;
dd[new[] { "a", "b" }]++;
Console.WriteLine(dd[new[] { "a", "b" }]);
The problem is that array equality is reference equality. In other words, it does not depend on the values stored in the array, it depends only on the identity of the array.
Some solutions
use Tuple to hold the row data
use an anonymous type to hold the row data
create a custom type to hold the row data, and, if it is a class, override Equals and GetHashCode.
create a custom implementation of IEqualityComparer to compare the arrays according to their values, and pass that to the dictionary when you create it.

Maintaining proper order of a collection of ordinals

I have a simple domain object:
class FavoriteFood
{
public string Name;
public int Ordinal;
}
I want to have a collection of this domain object that maintains the correct ordinal. For example, given 4 favorite foods:
Name: Banana, Ordinal: 1
Name: Orange, Ordinal: 2
Name: Pear, Ordinal: 3
Name: Watermelon, Ordinal: 4
If I change Pear's ordinal to 4 it should shift Watermelon's ordinal down to 3.
If I add a new favorite food (Strawberry) with ordinal 3 it should shift Pear up to 4 and Watermelon up to 5.
If I change Pear's ordinal to 2 it should shift Orange up to 3.
If I change Watermelon's ordinal to 1, Banana would bump up to 2, Orange would bump up to 3, and Pear would bump up to 4.
What's the best way to accomplish this?
UPDATE: The name property of the domain object is dynamic and based on user input. The object has to have this Ordinal property because a user can change the order in which their favorite foods are displayed. This ordinal value is saved in a database and when populating the structure I cannot guarantee the items are added in order of their ordinals.
The trouble I am running into is when the underlying domain object is changed, there isn't a good way of updating the rest of the items in the list. For example:
var favoriteFoods = new List<FavoriteFood>();
var banana = new FavoriteFood { Name = "Banana", Ordinal = 1};
favoriteFoods.Add(banana);
favoriteFoods.Add(new FavoriteFood { Name = "Orange", Ordinal = 2 });
banana.Ordinal = 2;
// at this point both Banana and Orange have the same ordinal in the list. How can we make sure that Orange's ordinal gets updated too?
So far I have tried doing the following which works :
class FavoriteFood : INotifyPropertyChanging
{
public string Name;
public int Ordinal
{
get { return this.ordinal; }
set
{
var oldValue = this.ordinal;
if (oldValue != value && this.PropertyChanging != null)
{
this.PropertyChanging(new FavoriteFoodChangingObject { NewOrdinal = value, OldOrdinal = oldValue }, new PropertyChangingEventArgs("Ordinal"));
}
this.ordinal = value;
}
}
internal struct FavoriteFoodChangingObject
{
internal int NewOrdinal;
internal int OldOrdinal;
}
// THIS IS A TEMPORARY WORKAROUND
internal int ordinal;
public event PropertyChangingEventHandler PropertyChanging;
}
public class FavoriteFoodCollection : IEnumerable<FavoriteFood>
{
private class FavoriteFoodOrdinalComparer : IComparer<FavoriteFood>
{
public int Compare(FavoriteFood x, FavoriteFood y)
{
return x.Ordinal.CompareTo(y.Ordinal);
}
}
private readonly SortedSet<FavoriteFood> underlyingList = new SortedSet<FavoriteFood>(new FavoriteFoodOrdinalComparer());
public IEnumerator<FavoriteFood> GetEnumerator()
{
return this.underlyingList.GetEnumerator();
}
public void AddRange(IEnumerable<FavoriteFood> items)
{
foreach (var i in items)
{
this.underlyingList.Add(i);
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
private void UpdateOrdinalsDueToRemoving(FavoriteFood item)
{
foreach (var i in this.underlyingList.Where(x => x.Ordinal > item.Ordinal))
{
i.ordinal--;
}
}
public void Remove(FavoriteFood item)
{
this.underlyingList.Remove(item);
this.UpdateOrdinalsDueToRemoving(item);
}
public void Add(FavoriteFood item)
{
this.UpdateOrdinalsDueToAdding(item);
this.underlyingList.Add(item);
item.PropertyChanging += this.item_PropertyChanging;
}
private void item_PropertyChanging(object sender, PropertyChangingEventArgs e)
{
if (e.PropertyName.Equals("Ordinal"))
{
var ordinalsChanging = (FavoriteFood.FavoriteFoodChangingObject)sender;
this.UpdateOrdinalsDueToEditing(ordinalsChanging.NewOrdinal, ordinalsChanging.OldOrdinal);
}
}
private void UpdateOrdinalsDueToEditing(int newOrdinal, int oldOrdinal)
{
if (newOrdinal > oldOrdinal)
{
foreach (var i in this.underlyingList.Where(x => x.Ordinal <= newOrdinal && x.Ordinal > oldOrdinal))
{
//i.Ordinal = i.Ordinal - 1;
i.ordinal--;
}
}
else if (newOrdinal < oldOrdinal)
{
foreach (var i in this.underlyingList.Where(x => x.Ordinal >= newOrdinal && x.Ordinal < oldOrdinal))
{
//i.Ordinal = i.Ordinal + 1;
i.ordinal++;
}
}
}
private void UpdateOrdinalsDueToAdding(FavoriteFood item)
{
foreach (var i in this.underlyingList.Where(x => x.Ordinal >= item.Ordinal))
{
i.ordinal++;
}
}
}
This works alright, but the use of the internal Ordinal field is a strange workaround. It's needed so that the PropertyChangingEvent wont be infinitely raised.
Just use a List<string>:
List<string> foods = new List<string> { "Banana", "Orange", "Pear" };
int ordinalOfOrange = foods.IndexOf("Orange");
It's not a good idea to 'store' that ordinal if it has to change the way you describe.
Sounds like you want a SortedList. Add each item using it's Ordinal as the key.
I'd do something like the following:
public class FavoriteFoods
{
StringComparer comparer ;
List<string> list ;
public FavoriteFoods()
{
this.list = new List<string>() ;
this.comparer = StringComparer.InvariantCultureIgnoreCase ;
return ;
}
public void Add( string food , int rank )
{
if ( this.list.Contains(food,comparer ) ) throw new ArgumentException("food") ;
this.list.Insert(rank,food) ;
return ;
}
public void Remove( string food )
{
this.list.Remove( food ) ;
return ;
}
public void ChangeRank( string food , int newRank )
{
int currentRank = this.list.IndexOf(food) ;
if ( currentRank < 0 ) throw new ArgumentOutOfRangeException("food") ;
if ( newRank < 0 ) throw new ArgumentOutOfRangeException("newRank") ;
if ( newRank >= this.list.Count ) throw new ArgumentOutOfRangeException("newRank") ;
if ( newRank != currentRank )
{
this.Remove(food) ;
this.Add( food , newRank ) ;
}
return ;
}
public int GetRank( string food )
{
int rank = this.list.IndexOf(food) ;
if ( rank < 0 ) throw new ArgumentOutOfRangeException("food");
return rank ;
}
public IEnumerable<string> InRankOrder()
{
foreach ( string food in this.list )
{
yield return food ;
}
}
}
Let me restate your problem.
You have a collection of strings. You have a collection of ordinals.
You want to be able to quickly look up the ordinal of a string. And the string of an ordinal. You'd also like to be able to insert a string with a given ordinal. And change the ordinal of a string.
There are two ways to go. The first, simple, approach is to store a collection of the strings in order, with knowledge of their ordinal. You can scan the list in time O(n). You can also lookup, insert, move, and delete in time O(n) each. If you don't actually care about performance then I would strongly suggest going this way.
If you do care about performance, then you'll need to build a custom data structure. The simplest idea is to have two trees. One tree stores the strings in alphabetical order, and tells you where in the other tree the string is. The other tree stores the strings in order of the ordinals, and stores counts of how much stuff is in various subtrees.
Now here are your basic operations.
Insert. Insert in the second tree at the correct position (if you choose to move anything else in the process, updating those things in the first tree), then insert the string in the first tree.
Lookup by string. Search the first tree, find where it is in the second tree, walk back in the second tree to find its ordinal.
Lookup by ordinal. Search the second tree, find the string.
Delete. Delete from both trees.
Move ordinal. Remove from the second tree in the old position. Insert into the second tree in the new position. Update all appropriate nodes in the first tree.
For the simple version you can just use trees. If you want to get fancy, you can look up B-Trees, Red-Black trees and other types of self-balancing trees, then pick one of those.
If you program this correctly you can guarantee that all operations take time O(log(n)). However there will be a lot of constant overhead, and for small collections the effort to be clever may be a loss relative to the simple approach.

What is the least amount of code needed to update one list with another list?

Suppose I have one list:
IList<int> originalList = new List<int>();
originalList.add(1);
originalList.add(5);
originalList.add(10);
And another list...
IList<int> newList = new List<int>();
newList.add(1);
newList.add(5);
newList.add(7);
newList.add(11);
How can I update originalList so that:
If the int appears in newList, keep
If the int does not appear in newList, remove
Add any ints from newList into originalList that aren't there already
Thus - making the contents of originalList:
{ 1, 5, 7, 11 }
The reason I'm asking is because I have an object with a collection of children. When the user updates this collection, instead of just deleting all children, then inserting their selections, I think it would be more efficient if I just acted on the children that were added or removed, rather than tearing down the whole collection, and inserting the newList children as if they are all new.
EDIT - Sorry - I wrote a horrible title... I should have written 'least amount of code' instead of 'efficient'. I think that threw off alot of the answers I've gotten. They are all great... thank you!
originalList = newList;
Or if you prefer them being distinct lists:
originalList = new List<int>(newList);
But, either way does what you want. By your rules, after updating, originalList will be identical to newList.
UPDATE: I thank you all for the support of this answer, but after a closer reading of the question, I believe my other response (below) is the correct one.
If you use some LINQ extension methods, you can do it in two lines:
originalList.RemoveAll(x => !newList.Contains(x));
originalList.AddRange(newList.Where(x => !originalList.Contains(x)));
This assumes (as do other people's solutions) that you've overridden Equals in your original object. But if you can't override Equals for some reason, you can create an IEqualityOperator like this:
class EqualThingTester : IEqualityComparer<Thing>
{
public bool Equals(Thing x, Thing y)
{
return x.ParentID.Equals(y.ParentID);
}
public int GetHashCode(Thing obj)
{
return obj.ParentID.GetHashCode();
}
}
Then the above lines become:
originalList.RemoveAll(x => !newList.Contains(x, new EqualThingTester()));
originalList.AddRange(newList.Where(x => !originalList.Contains(x, new EqualThingTester())));
And if you're passing in an IEqualityOperator anyway, you can make the second line even shorter:
originalList.RemoveAll(x => !newList.Contains(x, new EqualThingTester()));
originalList.AddRange(newList.Except(originalList, new EqualThingTester()));
Sorry, wrote my first response before I saw your last paragraph.
for(int i = originalList.length-1; i >=0; --i)
{
if (!newList.Contains(originalList[i])
originalList.RemoveAt(i);
}
foreach(int n in newList)
{
if (!originaList.Contains(n))
originalList.Add(n);
}
If you are not worried about the eventual ordering, a Hashtable/HashSet will likely be the fastest.
LINQ solution:
originalList = new List<int>(
from x in newList
join y in originalList on x equals y into z
from y in z.DefaultIfEmpty()
select x);
My initial thought was that you could call originalList.AddRange(newList) and then remove the duplicates - but i'm not sure if that would be any more efficient than clearing the list and repopulating it.
List<int> firstList = new List<int>() {1, 2, 3, 4, 5};
List<int> secondList = new List<int>() {1, 3, 5, 7, 9};
List<int> newList = new List<int>();
foreach (int i in firstList)
{
newList.Add(i);
}
foreach (int i in secondList)
{
if (!newList.Contains(i))
{
newList.Add(i);
}
}
Not very clean -- but it works.
There is no built in way of doing this, the closest I can think of is the way DataTable handles new and deleted items.
What #James Curran suggests is merely replace the originalList object with the newList object. It will dump the oldList, but keep the variable (i.e. the pointer is still there).
Regardless, you should consider if optimising this is time well spent. Is the majority of the run time spent copying values from one list to the next, it might be worth it. If it's not, but rather some premature optimising you are doing, you should ignore it.
Spend time polishing the GUI or profile the application before you start optimising is my $.02.
This is a common problem developers encounter when writing UIs to maintain many-to-many database relationships. I don't know how efficient this is, but I wrote a helper class to handle this scenario:
public class IEnumerableDiff<T>
{
private delegate bool Compare(T x, T y);
private List<T> _inXAndY;
private List<T> _inXNotY;
private List<T> _InYNotX;
/// <summary>
/// Compare two IEnumerables.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="compareKeys">True to compare objects by their keys using Data.GetObjectKey(); false to use object.Equals comparison.</param>
public IEnumerableDiff(IEnumerable<T> x, IEnumerable<T> y, bool compareKeys)
{
_inXAndY = new List<T>();
_inXNotY = new List<T>();
_InYNotX = new List<T>();
Compare comparer = null;
bool hit = false;
if (compareKeys)
{
comparer = CompareKeyEquality;
}
else
{
comparer = CompareObjectEquality;
}
foreach (T xItem in x)
{
hit = false;
foreach (T yItem in y)
{
if (comparer(xItem, yItem))
{
_inXAndY.Add(xItem);
hit = true;
break;
}
}
if (!hit)
{
_inXNotY.Add(xItem);
}
}
foreach (T yItem in y)
{
hit = false;
foreach (T xItem in x)
{
if (comparer(yItem, xItem))
{
hit = true;
break;
}
}
if (!hit)
{
_InYNotX.Add(yItem);
}
}
}
/// <summary>
/// Adds and removes items from the x (current) list so that the contents match the y (new) list.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="compareKeys"></param>
public static void SyncXList(IList<T> x, IList<T> y, bool compareKeys)
{
var diff = new IEnumerableDiff<T>(x, y, compareKeys);
foreach (T item in diff.InXNotY)
{
x.Remove(item);
}
foreach (T item in diff.InYNotX)
{
x.Add(item);
}
}
public IList<T> InXAndY
{
get { return _inXAndY; }
}
public IList<T> InXNotY
{
get { return _inXNotY; }
}
public IList<T> InYNotX
{
get { return _InYNotX; }
}
public bool ContainSameItems
{
get { return _inXNotY.Count == 0 && _InYNotX.Count == 0; }
}
private bool CompareObjectEquality(T x, T y)
{
return x.Equals(y);
}
private bool CompareKeyEquality(T x, T y)
{
object xKey = Data.GetObjectKey(x);
object yKey = Data.GetObjectKey(y);
return xKey.Equals(yKey);
}
}
if your using .Net 3.5
var List3 = List1.Intersect(List2);
Creates a new list that contains the intersection of the two lists, which is what I believe you are shooting for here.

Categories