Remove Duplicate entries from a 2D list in CSharp - c#

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.

Related

Is there a way to change multiple Dictionary values at once in C#?

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

Instantiating a List

If I want to instantiate a array the syntax is
int[] items = new int[] { 1, 2, 3 };
and the shortcut is
int[] items = {1,2,3};
Now I want to do the same to a List.
Question:
why does this work:
List<int> items = new int[] { 1, 2, 3 }.ToList();
but not this:
List<int> items = { 1, 2, 3 }; //invalid
or
List<int> items = { 1, 2, 3 }.ToList(); //invalid
The syntax
int[] array = {1,2,3};
is special syntactic sugar for array initialization. {1,2,3} is not itself an array yet.
This line
List<int> list = new[] {1,2,3}.ToList();
works because the expression new[] {1,2,3} returns an int[], which implements IEnumerable<int> and so you can call ToList() on it.
In the specs that's the difference between 12.6 Array initializers and 7.5.10.2 Array creation expressions.
List<T> has a constructor that takes an IEnumerable<T> as argument to initialize the list's content with. So you can either call
List<int> list = new List<int>(new[]{1,2,3});
or use the collection initializer syntax sugar:
List<int> list = new List<int> {1,2,3};
which is converted by the compiler to something like this:
var tmp = new List<int>();
tmp.Add(1);
tmp.Add(2);
tmp.Add(3);
List<int> list = tmp;

using TryGetValue from key and adding not working as intened

I have this code to retrieve a value(integer array) out of a dictionary Then increment one of the elements inside the integer array based on the if statement it is in..
Dictionary<string, int[]> ResultDic = new Dictionary<string, int[]>();
if (TeamOnePoint > TeamTwoPoint)
{
ResultDic.TryGetValue(TeamOneResult, out OutOfDic);
OutOfDic[0]++;
OutOfDic[1]++;
////ResultDic.Remove(TeamOneResult);
////ResultDic.Add(TeamOneResult, OutOfDic);
ResultDic[TeamOneResult] = OutOfDic;;
ResultDic.TryGetValue(TeamTwoResult, out OutOfDic);
OutOfDic[0]++;
OutOfDic[2]++;
////ResultDic.Remove(TeamTwoResult);
////ResultDic.Add(TeamTwoResult, OutOfDic);
ResultDic[TeamTwoResult] = OutOfDic;
}
Now the problem I have is that evertime I read the modified OutOfDic array back into the dictionary into the value part where I specified the Key, every value in the dictionary is modified as well, and not just the key I specified.
The commented part gives the same result as the non commented part. How do I fix this problem to only add the value to the specified key?
The behaviour you've described is only possible if you've added the same array to the dictionary multiple times. Since arrays are reference types every change will affect all values in the dictionay.
So instead of doing this(for example):
Dictionary<string, int[]> ResultDic = new Dictionary<string, int[]>();
int[] array = { 1, 2, 3, 4, 5 };
ResultDic.Add("TeamOne", array);
ResultDic.Add("TeamTwo", array);
You should do this:
int[] array = { 1, 2, 3, 4, 5 };
ResultDic.Add("TeamOne", array);
array = new int[] { 1, 2, 3, 4, 5 };
ResultDic.Add("TeamTwo", array);
Note that it's not necessary to re-assign the array to the dictionary for the same reason (it's a reference type). So you can remove these lines:
ResultDic[TeamOneResult] = OutOfDic;;
// ....
ResultDic[TeamTwoResult] = OutOfDic;

IEnumerable - exclude using an array

Does anyone know if it's possible to create a new IEnumerable by using an array parameter to exclude values.
For instance, below is an example of how I imagine it would look.
class Item
{
public int id { get; set; }
public string name { get; set; }
}
IEnumerable looks like this:
item1 {id = 1}
item2 {id = 2}
item3 {id = 3}
I want to create a new IEnumerable but exclude the id numbers in the array.
Made up code to suggest idea:
Int32[] arrayList = {1,2};
var newIEnumerable = _exisitingIEnumerable.Where(o => (o.id NOT IN arrayList));
Looking at your question again, when the element type of _exisitingIEnumerable is not the same as that of arrayList, you will need to use Where to filter out the elements of arrayList
_exisitingIEnumerable.Where(o => !arrayList.Contains(o.Id))
Original answer:
_exisitingIEnumerable.Except(arrayList)
will return the distinct elements from _exisitingIEnumerable that are not in arrayList
If you need duplicates, you can use
_exisitingIEnumerable.Where(o => !arrayList.Contains(o))
What's wrong with the approach you suggested in the question? You can use Where and check if the array contains the value. Below the example using List as a target collection:
var myList = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8 };
int[] myArray = { 1, 2, 3 };
var result = new List<int>(myList.Where(n => !myArray.Contains(n)));

How do I update/add items in/to an IObservable<int> dynamically?

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.

Categories