How to compare Lists of Guids in C# - c#

I have got this structure
var values = new Dictionary<int, List<Guid>>();
And I have to say if all dictionary elements has the same set of List<Guid>.
I dont need to know which are exactly are different, just to answer the question.
So it looks like
List A { 1, 2, 3} List B { 1, 2, 3} List C { 1, 2, 3} the same and have no difference.
and
List A { 3, 2, 3} List B { 1, 2, 3} List C { 1, 2, 3} are not the same.
I have no clue where I can start it.
Initially i guessed to convert List<Guid> to string and just do distinct operation over it.
But is this a good approach?
Thank you!

I'd create a HashSet<Guid> from one of the values (any) and then check that all of the others are equal to it:
// TODO: Handle the dictionary being empty
var firstSet = new HashSet<Guid>(values.First().Value);
var allEqual = values.All(pair => firstSet.SetEquals(pair.Value));
This assumes that:
The order within each list is unimportant
The number of times each GUID appears in the list is unimportant
(i.e. you really are thinking of them as sets, not lists, at least for this part of the code)
In other words, if you have guids A and B, the code above assumes that { A, B, B } is equivalent to { B, A }.

SequenceEquals() might be what you're looking for. Combine it with IEnumerable.All() and you can get a boolean answer whether all elements of your dictionary contain the same Lists. For instance:
values.All(list => values.All(list2 => list2.SequenceEquals(list));

Related

PriorityQueue containing array C#

I would like to create a PriorityQueue to store int[]. The first element in the array is gonna be the criteria for the comparisons.
I could do that easily in Java, though I could not convert it to C#. Could you please guide me?
Priority queues don't work the same way in both languages. What you're trying to do is the Java way of giving PQ a lambda (function) to compare any two elements. In C#, you give each element a priority when adding it to the queue, and then make a comparer to compare different priorities.
PriorityQueue<int[], int> pq = new(Comparer<int>.Create((a, b) => a - b));
// The Comparer compares the *priorities*, not the elements
pq.Enqueue(new int[] { 1, 2, 3, 4 }, 5);
pq.Enqueue(new int[] { 1, 2, 3, 4 }, 0); // This has more priority
while (pq.TryDequeue(out int[]? arr, out int priority))
{
Console.WriteLine(priority); // 0; 5
}
You may be interested in just a simple List and LINQ:
using System.Linq; // at the top of your code to include LINQ
List<int[]> list = new();
list.Add(new int[] { 1, 2, 3, 4 });
list.Add(new int[] { 5, 2, 3, 4 });
IEnumerable<int[]> ordered = list.OrderBy(x => x[0]); // orders by the first element

Does LINQ have any easy/elegant way to take the first element and put it at the end?

Or should I say, skip the first element and come back to it at the end.
e.g. say I have
int[] arr = { 2, 4, 3, 9, 1, 0 };
and want to iterate through it like
{ 4, 3, 9, 1, 0, 2 }
I know one way would be like
foreach(int i in arr.Skip(1).Append(new int[] { arr.First() }))
which is why I'm asking whether there's a better looking and/or more efficient way.
Only slightly cleaner than what you've got:
foreach(int i in arr.Skip(1).Concat(arr.Take(1)))
{
...
}
Another way. (not cleaner tho)
Enumerable.Range(1, arr.Length)
.Select(x => arr[x%arr.Length]);
I would hold it into a new collection, like a list, since it will be more ckear what I am doing when somebody else will read my code (if ever). A list is well optimized for this kind of behavior:
var list = arr.ToList();
list.Add(list.ElemntAt(0));
list.RemoveAt(0);
Then you can iterate the list, and it is more verbose to do it this way rather than using a Linq query, which can solve this problem, but it may not be so easy to read.

Getting a continuous chain of values based on a condition in LINQ

Say I have a List of numbers:
var list = new List<int>{100, 1, 2, 4, 10, 11, 50, 54};
And I want the output to be sets of numbers that satisfy a condition of "closeness" with its adjacent values.
So for example, if I define the distance between adjacent numbers to be less than 5, I will get something like:
Set1: {100}
Set2: {1, 2, 4}
Set3: {10, 11}
Set4: {50, 54}
Since the numbers in each set are within 5 of its adjacent value.
How would I do this in LINQ? I was thinking of some combination of Aggregate() and TakeWhile() but I couldn't figure it out.
To be clear, I am looking for a generic way of solving this (i.e. an algorithm that if I change 5 to any other number would also give an output of sets that satisfy the new condition).
I'm sure there are better approaches, since you want to do it with Linq you could do something like this.
int gid=0, prevvalue = list[0];
va result = list.Select(x=>
{
var obj = Math.Abs(prevvalue-x)>=10?
new {gid= ++gid, item =x}
:new {gid= gid, item =x};
prevvalue= x;
return obj;
})
.GroupBy(x=>x.gid)
.Select(x=>x.Select(s=>s.item).ToList())
.ToArray();
Check this Demo

Binary Search on the first element in a multiple dimensional array

My goal is to perform a binary search for only the first element in a 2D array. I have been searching all day to find if it is possible using BinarySearch() in .NET but I can't find a thing.
To make this clearer. Imagine I had a 1D array, unsorted. If I sort the array, I lose the original index. I would like to create a second element of my array to hold the original index (this I can do) then sort by first element, then binary search over the first elements.
If anyone could push me in the right direction I'd be very grateful.
Thanks
Well, if I understand you correctly, you need something like this:
// initialize the array and the indexes array
var a2D = new int[2][];
a2D[0] = new[] { 3, 14, 15, 92, 65, 35 }; // <-- your array (fake data here)
a2D[1] = Enumerable.Range(0, a2D[0].Length).ToArray(); // create the indexes row
// sort the first row and the second one containing the indexes
Array.Sort(a2D[0], a2D[1]);
// now a2D array contains:
// row 0: 3, 14, 15, 35, 65, 92
// row 1: 0, 1, 2, 5, 4, 3
// and you can perform binary search on the first row:
int columnIndexOf35 = Array.BinarySearch(a2D[0], 35);
// columnIndexOf35 = 3
//
// a2D[0][columnIndexOf35] = 35 <- value
// a2D[1][columnIndexOf35] = 5 <- original index
As per MSDN, Array.BinarySearch method operates only with one-dimensional arrays, so it is impossible to use it directly in your case. Some of the options you have are:
Extract first column into a separate array and call Array.BinarySearch on it.
Define custom class Pair that implements interface IComparable and construct your array with the instances of this class.
Implement binary search on two dimensional array by yourself.
It looks like you want to have object that holds data and "original index" and than sort/search array of objects by data.
(This answer shows Andrei's option 2)
class IndexedData:IComparable
{
public MyType Data;
public int OriginalIndex;
public int CompareTo(object obj) {
// add correct checks for null,.. here
// and return correct comparison result.
// I.e. if MyType is IComparable - just delegate.
return Data.CompareTo(obj);
}
Check IComparable on MSDN for implementation/usage details.
Depending on what you're planning to do with the arrays afterwards, another solution might be to use LINQ.
var unsortedStartingArray = new[] {3, 6, 2, 1, 20, 20};
var q = unsortedStartingArray
.Select((item, index) => new {item, index})
.ToLookup(x => x.item, x => x.index);
var notFound = q[30]; // An empty array. Nothing found
var indexOf1 = q[1].First(); // returns 3
var multipleIndexsOf20 = q[20]; // Returns an array with 4, 5
The index into the lookup would then be the value you're searching for. Performance wise I would guesstimate this to be faster aswell about 5 times slower from my crude testing.

Comparing two sets for new and missing keys

When comparing two key-value dictionary sets in C#: set A and set B, what is the best way to enumerate keys present in set A but missing from set B and vice-versa?
For example:
A = { 1, 2, 5 }
B = { 2, 3, 5 }
Comparing B with A, missing keys = { 1 } and new keys = { 3 }.
Using Dictionary<...,...> objects, one can enumerating all values in B and test against set A using A.ContainsKey(key);, but it feels like there should be a better way that might involve a sorted set?
I'm aware of two built-in ways of doing set differences.
1) Enumerable.Except
Produces the set difference of two sequences by using the default equality comparer to compare values.
Example:
IEnumerable<int> a = new int[] { 1, 2, 5 };
IEnumerable<int> b = new int[] { 2, 3, 5 };
foreach (int x in a.Except(b))
{
Console.WriteLine(x); // prints "1"
}
2a) HashSet<T>.ExceptWith
Removes all elements in the specified collection from the current HashSet<T> object.
HashSet<int> a = new HashSet<int> { 1, 2, 5 };
HashSet<int> b = new HashSet<int> { 2, 3, 5 };
a.ExceptWith(b);
foreach (int x in a)
{
Console.WriteLine(x); // prints "1"
}
2b) HashSet<T>.SymmetricExceptWith
Modifies the current HashSet<T> object to contain only elements that are present either in that object or in the specified collection, but not both.
HashSet<int> a = new HashSet<int> { 1, 2, 5 };
HashSet<int> b = new HashSet<int> { 2, 3, 5 };
a.SymmetricExceptWith(b);
foreach (int x in a)
{
Console.WriteLine(x); // prints "1" and "3"
}
If you need something more performant, you'll probably need to roll your own collection type.
Use SortedDictionary : logic is A.Except(A.Intersect(B)).
Don't worry overmuch about performance until you've determined it is an issue to your datasets.
you can use the Except method.
Dictionary<string, string> dic1 = new Dictionary<string, string>() { { "rabbit", "hat" }, { "frog", "pond" }, { "cat", "house" } };
Dictionary<string, string> dic2 = new Dictionary<string, string>() { { "rabbit", "hat" }, { "dog", "house"}, {"cat", "garden"}};
var uniqueKeys = dic1.Keys.Except(dic2.Keys);
foreach (var item in uniqueKeys)
{
Console.WriteLine(item);
}
So there are several answers here that will work. But your original question is best addressed in two parts:
Q) When comparing two key-value dictionary sets in C#: set A and set B, what is the best way to enumerate keys present in set A but missing from set B and vice-versa? Using Dictionary<...,...> objects, one can enumerating all values in B and test against set A using A.ContainsKey(key);, ...
If your starting with two dictionaries this may be the best approach. To do anything else would require creating a copy of the keys from both sets, thus making most alternatives more expensive.
Q) ...but it feels like there should be a better way that might involve a sorted set?
Yes this can be done with a sorted list easily enough. Create two List insertion sorted with BinarySearch, then walk set 1 while searching set 2 ect.
See this SetList Complement and Subtract operations:
http://csharptest.net/browse/src/Library/Collections/SetList.cs#234

Categories

Resources