If so, what is it?
EDIT: In response to comment below:
var tabulatedOutputErrors = from error in outputErrors
group error by error into errorGroup
select new { error = errorGroup.Key, number = errorGroup.Count() };
var tabulatedInputErrors = from error in inputErrors
group error by error into errorGroup
select new { error = errorGroup.Key, number = errorGroup.Count() };
var problems = tabulatedOutputErrors.Except(tabulatedInputErrors);
You can expand out the counts if you need to.
LINQ has the Enumerable.Except extension method, which seems to be what you're looking for.
Example:
var list1 = new int[] {1, 3, 5, 7, 9};
var list2 = new int[] {1, 1, 5, 5, 5, 9};
var result = list1.Except(list2); // result = {3, 7}
Alternative:
From .NET 3.5 onwards there also exists the HashSet<T> class (and also the similar SortedSet<T> class in .NET 4.0. This class (or rather the ISet<T> interface in .NET 4.0) has an ExceptWith method which could also do the job.
Example:
var set1 = new HashSet<int>() {1, 3, 5, 7, 9};
var set2 = new HashSet<int>() {1, 1, 5, 5, 5, 9};
set1.ExceptWith(set2); // set1 = {3, 7}
Of course, it depends on the context/usage whether this approach is more desirable. The efficiency benefit (doing the difference operation in-place and using hash codes) in most cases is probably negligible. Either way, take your pick. :)
Related
How do I remove duplicate entries from a 2D list in C#.
here is my code.
HashSet<List<int>> set = new HashSet<List<int>>();
set.Add(new List<int>(){1,-2,-1,2});
set.Add(new List<int>(){3,-2,1,1});
set.Add(new List<int>() {1,-2,-1,2}); //duplicate entry
but the result i get from this has the duplicate entry {{1,-2,-1,2},{3,-2,1,1},{1,-2,-1,2}} i also tried using set.Distinct().ToList() but i still get duplicates in my result.
please can someone point me to a neat way to get this done using HashSet. I don't want to compare each sequence in the list because that adds some time complexity to my code.
Thanks for your help in anticipation.
You can write your own implementation of IEqualityComparer<List<int>> (and use a SequenceEqual method for list equality)
public class ListComparer : IEqualityComparer<List<int>>
{
public bool Equals(List<int> x, List<int> y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(List<int> obj)
{
return obj.Aggregate(19, (current, item) => current ^ item.GetHashCode());
}
}
Then pass its instance to Distinct method
var set = new HashSet<List<int>>
{
new List<int>() {1, -2, -1, 2}, new List<int>() {3, -2, 1, 1}, new List<int>() {1, -2, -1, 2}
};
var result = set.Distinct(new ListComparer());
It allows you to remove {1,-2,-1,2} duplicated entry.
You can also pass ListComparer instance to HashSet constructor and get rid of adding a duplicate lists
var set = new HashSet<List<int>>(new ListComparer())
{
new List<int>() {1, -2, -1, 2}, new List<int>() {3, -2, 1, 1}, new List<int>() {1, -2, -1, 2}
};
In example above set will contain only two items without duplicated lists
you can create an implementation of IEqualityComparer and pass it to Distinct function.
in you implementation of IEqualityComparer order the list and check for except (or intersect) if there is any then the two list is not equals.
you can also do a simple loop through each list, and check for item in same index if number of same keys are equal to your list length then eliminate on of them.
I have a class with a Dictionary property containing a long list of boolean values that default to false in the constructor. After the object is created I need to change some amount of these to true depending on other factors, my question is, is there a more efficient way to change multiple values to true than a list of value assignments?
EDIT:
I'm helping a student create a game, he has Room object and each room has 8 possible exits. He wants to define each room's exits individually the way he thinks they should be. He decided to make it a Dictionary and he was then defining a Dictionary with 8 true/false values in each Room constructor. I suggested starting with a Dictionary of all falses and only changing the ones he needed to be true (a small percentage of most). Since there is no pattern loops and functions don't really work for what he's trying to do, he needs to enter it manually but I was looking for a way to DRY his code up.
Dictionary<int, bool> dict = new Dictionary<int, bool>()
{
{1, false},
{2, false},
{3, false},
{4, false},
{5, false},
{6, false},
{7, false},
{8, false}
};
myObject1.dict[1] = true;
myObject1.dict[3] = true;
myObject1.dict[4] = true;
myObject2.dict[3] = true;
myObject3.dict[1] = true;
myObject3.dict[5] = true;
...
I doubt that there's a more efficient way but there's a more "compact" way, without looping through all of the keys of each dictionary :
var dict = new Dictionary<int, bool>()
{
{1, false},
{2, false},
{3, false},
{4, false},
{5, false},
{6, false}
};
new List<int> { 1, 3, 4 }.ForEach(i => myObject1.dict[i] = true);
new List<int> { 3 }.ForEach(i => myObject2.dict[i] = true);
new List<int> { 1, 5 }.ForEach(i => myObject3.dict[i] = true);
You could write a method such as this:
void SetMultipleKeyValues(Dictionary<int,bool> dictionary, bool value, params int[] keys)
{
foreach(int key in keys)
{
dictionary[key] = value;
}
}
It's a simplistic example, you could make it a generic extension method, use LINQ instead of a foreach loop, etc. It would encapsulate the looping well so that you aren't replicating it everywhere you need to set the list of values in your dictionary.
Jeff
You can use Linq to update multiple records in a dictionary based on a condition.
Following example simply changes the values of every even numbered key. You can use your own condition in the Where clause to get the specific keys that you need to update.
dict.Where(x => x.Key % 2 == 0).ToList().ForEach(x => dict[x.Key] = true);
Randomly choose the doors
You can also work it out where you update the dictionary based on certain random numbers.
int numOfDoors = 4;
List<int> randomNumber = Enumerable.Range(0, numOfDoors).Select(x => new Random().Next(1, dict.Count())).ToList();
dict.Where(x => randomNumber.Contains(x.Key)).ToList().ForEach(x => dict[x.Key] = true);
I initially had some code, which when simplified, looks like this:
var planets = new List<Planet>
{
new Planet {Id = 1, Name = "Mercury"},
new Planet {Id = 2, Name = "Venus"},
};
I got into a scenario where the list was being populated all at once, but the reads weren't fast enough. And so, I changed this to use a SortedList instead.
I later realized that I could rewrite it like this
var planets = new SortedList<int, Planet>
{
{1, new Planet {Id = 1, Name = "Mercury"}},
{2, new Planet {Id = 2, Name = "Venus"}},
//in my actual code, i am reading the ids from a db
};
But before I got to this approach, I had the code written like this
var planets = new SortedList<int, Planet>
{
Keys = {1, 2},
Values =
{
new Planet {Id = 1, Name = "Mercury"},
new Planet {Id = 2, Name = "Venus"},
}
};
which gives me this exception
System.NotSupportedException: This operation is not supported on SortedList
nested types because they require modifying the original SortedList.
at System.ThrowHelper.ThrowNotSupportedException(ExceptionResource resource)
at System.Collections.Generic.SortedList`2.KeyList.Add(TKey key)
which I found to be very strange, coz IMHO, I wasn't really modifying the "original SortedList" as it claims, and what "nested types" is it talking about? Is it the list of keys internal to the SortedList?
I see then that the Keys and Values properties in SortedList don't actually have setters. They are read-only properties, and yet, I don't get a compile-time error. I am allowed to make a set call, as I can see in the stack trace with KeyList.Add. I feel the only reason why this fails is because of an explicit check within SortedList, which seems bizarre to me!
For instance
var str = new String {Length = 0}; gives me a compile-time error as expected, since Length is a read-only property, as does planets.Keys = null;
Someone please tell me - what simple fact am I overlooking here?
The code that you've written is comparable to this:
var planets = new SortedList<int, Planet>();
planets.Keys.Add(1);
planets.Keys.Add(2);
planets.Values.Add(new Planet { Id = 1, Name = "Mercury" });
planets.Values.Add(new Planet { Id = 2, Name = "Venus" });
SortedList requires that you add the value and key at the same time via SortedList<TKey, TValue>.Add(TKey key, TValue value) method, so that it can sort the value by the key. The implementation of the IList<T> which is used for Keys and Values internally does not support adding a respective key or value independently via the IList<T>.Add(T value) method.
You should be able to reproduce this error by calling Keys.Add(...) or Values.Add(...)
My initial query about the SortedList has now minimized to this concern about array, collection & object initializers, and the way the compiler interprets them differently. Thanks to #Haney again for the first answer to guide me towards this point of view, and to ILSpy for these insights.
Here are some array and collection initializers:
int[] a = { 1, 2, 3 };
int[] b = new int[] { 1, 2, 3 };
IList<int> c = { 1, 2, 3 };
IList<int> d = new int[] { 1, 2, 3 };
They all look kind of similar. Here, the compiler produces the exact same output for a & b. For c, we will get this compile-time error:
Can only use array initializer expressions to assign to array types.
Try using a new expression instead.
which makes sense since we shouldn't use array initializers for collections. But then, d produces the exact same result as a & b. And I thought that was an array initializer as well. Apparently not.
Now consider this class
class MyCollectionContainer
{
public int[] MyIntArray { get; set; }
public IList<int> MyList { get; set; }
}
and this code that operates on it
var containerA = new MyCollectionContainer { MyIntArray = { 1, 2, 3 } };
var containerB = new MyCollectionContainer { MyIntArray = new int[]{ 1, 2, 3 } };
var containerC = new MyCollectionContainer { MyList = { 1, 2, 3 } };
var containerD = new MyCollectionContainer { MyList = new int[]{ 1, 2, 3 } };
containerA gives this compile-time error:
Cannot initialize object of type 'int[]' with a collection initializer
For containerB, the compiler effectively converts it into this code:
MyCollectionContainer myCollectionContainer = new MyCollectionContainer();
myCollectionContainer.MyIntArray = new int[] {1, 2, 3};
For containerD, its pretty much the same, barring the fact that its another property that gets initialized:
MyCollectionContainer myCollectionContainer = new MyCollectionContainer();
myCollectionContainer.MyList = new int[] {1, 2, 3};
For containerC, the compiler morphs it into:
MyCollectionContainer myCollectionContainer = new MyCollectionContainer();
myCollectionContainer.MyList.Add(1);
myCollectionContainer.MyList.Add(2);
myCollectionContainer.MyList.Add(3);
This results in a run-time NullReferenceException since MyList is not initialized.
This means the only valid ways to initialize the collection container object here is containerB and containerD. To me, this clearly shows that object initializers are different when compared to array & collection initializers, in the way the compiler interprets them.
I have an observable collection to which I want to keep feeding objects and they should reach observers even after someone has subscribed to it (which ofcourse is the main aim of an observable). How do I do it?
In the following program, after the subscription has happened I want to feed in 3 more numbers which should reach observers. How do I do this?
I don't want to go via the route where I implement my own Observable class by implementing IObservable<int> and use Publish method? Is there any other way to achieve this?
public class Program
{
static void Main(string[] args)
{
var collection = new List<double> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var observableCollection = collection.ToObservable();
observableCollection.Subscribe(OnNext);
//now I want to add 100, 101, 102 which should reach my observers
//I know this wont' work
collection.Add(100);
collection.Add(101);
collection.Add(102);
Console.ReadLine();
}
private static void OnNext(double i)
{
Console.WriteLine("OnNext - {0}", i);
}
}
This is what I'd do:
var subject = new Subject<double>();
var collection = new List<double> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var observableCollection = collection
.ToObservable()
.Concat(subject); //at the end of the original collection, add the subject
observableCollection.Subscribe(OnNext);
//now I want to add 100, 101, 102 which should reach my observers
subject.OnNext(100);
subject.OnNext(101);
subject.OnNext(102);
Generally, if you can observe whatever is producing the additional input, you'd want to concat that observable, rather than imperatively pushing these values into a subject, but sometimes that's not practical.
That's it. The question is in the title
I was looking for a cleaner way than the using for...break;
thanks
This should do it!
var items = new List<int>(){ 1, 2, 3, 4, 5 };
var results = items.Take(3);