Is there a LINQ equivalent method? - c#

I know LINQ has a SequenceEquals method. This method makes sure each item value in each collection matches, in the same order.
What I'm looking for is a more "Equivalent" type of functionality. Just that both sequences contain the same items, not necessarily in the same order.
For example, nUnit has CollectionAssert.AreEqual() and CollectionAssert.AreEquivalent() that do what I'm explaining.
I know that I can do this either by:
Ordering the lists ahead of time and using SequenceEquals
Using Intersect, then seeing if the intersection is equal to the original sequence.
Example:
var source = new[] {5, 6, 7};
source.Intersect(new[] {5, 7, 6}).Count() == source.Length;

You could build a set and then use HashSet<T>.SetEquals. It's not strictly within LINQ, but it plays nicely with it :)
Of course, you could easily write your own extension method to extend this. Something like this:
public static bool SetEquals<T>(this IEnumerable<T> source, IEnumerable<T> other)
{
HashSet<T> hashSet = new HashSet<T>(source);
return hashSet.SetEquals(other); // Doesn't recurse! Calls HashSet.SetEquals
}
EDIT: As noted in comments, this ignores the number of times elements occur, as well as the ordering - so { 1, 2 } would be "set equal" to { 1, 2, 1, 2, 1, 1, 1 }. If that's not what you want, it'll get a little more complicated.

I would create an extension method that does the intersect and then compares the counts.

I did it this way:
public static bool SetEquivalent<T>(
this IEnumerable<T> aSet,
IEnumerable<T> anotherSet)
{
var diffA = aSet.Except(anotherSet).Count();
var diffB = anotherSet.Except(aSet).Count();
return diffA == diffB && diffA == 0;
}

Related

Using HashSet.orderBy() function

Trying to sort:
HashSet<int> objHash = new HashSet<int>();
objHash.Add(14);
objHash.Add(12);
objHash.Add(11);
objHash.Add(13);
HashSet contians method OrderBy() with definition:
IOrderEnumerable<int> IEnumerable<int>.OrderBy<int,TKey>(Func<int,TKey>keySelector)
Trying to understand description:
IOrderEnumerable<int>- function OrderBy() returns
IEnumerable<int> - extension method defined in IEnumerable<int>. Can I somehow see body of this method?
.OrderBy<int,TKey>(Func<int,TKey>keySelector) - keySelector is function delegate with parameter of type int that returns TKey
Please, correct where my description interpretation is wrong.
How to use this function to order items in objHash according custom defined rules?
You are reading the quick info on the function correctly. To sort by your custom logic, you need to define what will be the return type as Tkey and pass the function that matches the delegate. The order by will then sort based on the returned value.
public static void Main()
{
var h = new HashSet<int> () {1, 2, 3, 4, 5};
var d = h.OrderBy<int, int>(x => MyFunc(x));
foreach(var a in d)
Console.WriteLine(a); //will order based on the returned value of MyFunc(x). in descending order.
// output will be 5 4 3 2 1 instead of 1 2 3 4 5.
}
public static int MyFunc(int x)
{
return x * -1;
}
And of course, if your Tkey is an object, you should want to implement IComparable to tell how to sort that object.
The OrderBy() method accepts the elements of your collection of objects (in your case, it is an int collection) and it should return a key for each specific object in the collection. Those returned keys are what will be used to sort the collection. Notice that these returned keys should be comparable between each other, so that the sorting can be performed.
Let's say you want to sort your numbers, while separating even numbers from odd numbers. A naive way of doing this would be making OrderBy() return string-typed keys, while placing a "0" character prefix on even numbers and a "1" character prefix on odd numbers, like that:
Number Returned key
14 "014"
12 "012"
11 "111"
13 "113"
Then you can do it like:
var ordered = objHash.OrderBy(n => $"{n % 2}{n}");
foreach (var x in ordered)
Console.WriteLine($" {x}");
This would output numbers in the following order: 12, 14, 11, 13 (first the ordered even numbers, followed by the ordered odd numbers). Notice how the returned string keys were used for comparison/sorting of the set of numbers.
Of course the lexicographical ordering here only works fine because numbers have the same length... But again: this is just a naive example of how to use the OrderBy() method.
keySelector is function delegate with parameter of type int that
returns TKey
Yes this is correct.
How to use this function to order items in objHash according custom
defined rules?
Firstly, note that OrderBy is an extension method on IEnumerable and not a contained method of HashSet.
if you want to order the elements via the OrderBy extension method then you'd pass x => x as the keySelector function:
var orderedEnumerable = objHash.OrderBy(x => x); // or any other logic as long as the function takes an int and returns TKey
Note that this doesn't modify the source and it wouldn't make sense to sort a HashSet anyway as by definition it does not care about order.
As explicitly stated in the documentation:
The HashSet<T> class provides high-performance set operations. A set
is a collection that contains no duplicate elements, and whose
elements are in no particular order.
it then goes on to say:
A HashSet<T> collection is not sorted and cannot contain duplicate
elements. If order or element duplication is more important than
performance for your application, consider using the List<T> class
together with the Sort method.
Emphasis mine.
if you want to maintain a sorted set then consider using SortedSet as it's documented as:
Represents a collection of objects that is maintained in sorted order.

C# extension of Enumerable not working

I am trying to add an extension to Enumerable class. but it seems that the extension FindEven() is not picked by the C# compiler. When I build, the compiler spit error :
CS0117 'Enumerable' does not contain a definition for 'FindEven'
Here is my code:
namespace ConsoleApp1
{
static public class Program
{
static IEnumerable<int> FindEven(this IEnumerable<int> array, Func<int, bool> predicte)
{
foreach (var n in array)
{
if (predicte(n))
{
yield return n;
}
}
}
static public void Main(string[] args)
{
int[] numbers = new[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var result = Enumerable.Select(Enumerable.FindEven(numbers, n => n % 2 == 0), n => n);
foreach (var output in result)
Console.WriteLine(output);
Console.ReadLine();
}
}
}
Anything I did incorrectly here?
[edit]
What I am trying to do here is to see how the 'where' statement in the following LINQ works by making my own version of 'Where', which in this case is 'FindEven' (not a good name I have to admit).
var result = from element in numbers
where element % 2 == 0
select element;
I think if I replace 'FindEven' by 'Where' which is defined in Enumerable[from metadata]... It should be the way LINQ works. But I just can not get the code compiled.
Thanks
Per your edit, it seems you're trying to add your FindEven function to the Enumerable class, but that won't work. When you're calling Enumerable.Where, you're not calling an extension method, you're calling an actual static method that's defined in Enumerable. You can't extend that class that way, because extension methods can't extend static methods, that's not what they're for. They extend instance methods.
The equivalent in your code of calling Enumerable.Where is calling Program.FindEven. That's where the static method is defined. The magic of extension methods is having both Where and FindEven available for an instance of IEnumerable<int>, regardless of where they're defined.
Pre-edit
From the way you call the method, you seem to believe that the extension method adds a new static method to the Enumerable class. It doesn't work that way. The extension method you defined will "add" the method to any instance of IEnumerable<int>, so your code will look like this:
var result = numbers.FindEven(n => n % 2 == 0);
Note, though, that your FindEven doesn't actually FindEven - it just queries using the provided predicate, meaning it's exactly the same as the built-in LINQ Where function. A proper FindEven method would be:
static IEnumerable<int> FindEven(this IEnumerable<int> source)
{
return source.Where(n => n % 2 == 0);
}
This will return a lazily-evaluated IEnumerable<int> containing only the even numbers.
Also, your external Select method does nothing - it just maps every integer to itself, meaning it returns an enumerable that's completely equivalent to its input.
When you define an extension method, you have to call it as it was a member function of your this IEnumerable<int> array parameter
simply replace your call with
var result = Enumerable.Select(numbers.FindEven(n => n % 2 == 0), n => n);
Also note that you created an extension method for IEnumerable<int>, not for Enumerable class
As per your edit, you can use Where function.
namespace ConsoleApp1
{
static public class Program
{
static public void Main(string[] args)
{
int[] numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var result = numbers.Where(n => n % 2 == 0);
foreach (var output in result)
Console.WriteLine(output);
Console.ReadLine();
}
}
}

Performing function on each array element, returning results to new array

I'm a complete Linq newbie here, so forgive me for a probably quite simple question.
I want to perform an operation on every element in an array, and return the result of each of these operations to a new array.
For example, say I have an array or numbers and a function ToWords() that converts the numbers to their word equivalents, I want to be able to pass in the numbers array, perform the ToWords() operation on each element, and pass out a string[]
I know it's entirely possible in a slightly more verbose way, but in my Linq adventures I'm wondering if it's doable in a nice one-liner.
You can use Select() to transform one sequence into another one, and ToArray() to create an array from the result:
int[] numbers = { 1, 2, 3 };
string[] strings = numbers.Select(x => ToWords(x)).ToArray();
It's pretty straight forward. Just use the Select method:
var results = array.Select(ToWords).ToArray();
Note that unless you need an array you don't have to call ToArray. Most of the time you can use lazy evaluation on an IEnumerable<string> just as easily.
There are two different approaches - you can use Select extension method or you can use select clause:
var numbers = new List<int>();
var strings1 = from num in numbers select ToWords(num);
var strings2 = numbers.Select(ToWords);
both of them will return IEnumerable<>, which you can cast as you need (for example, with .ToArray() or .ToList()).
You could do something like this :
public static string[] ProcessStrings(int[] intList)
{
return Array.ConvertAll<int, string>(intList, new Converter<int, string>(
delegate(int number)
{
return ToWords();
}));
}
If it is a list then :
public static List<string> ProcessStrings(List<int> intList)
{
return intList.ConvertAll<string>(new Converter<int, string>(
delegate(int number)
{
return ToWords();
}));
}
Straight simple:
string[] wordsArray = array.ToList().ConvertAll(n => ToWords(n)).ToArray();
If you are OK with Lists, rather than arrays, you can skip ToList() and ToArray().
Lists are much more flexible than arrays, I see no reason on earth not to use them, except for specific cases.

How to get a consistent .Count / .Length property for C# generic collections?

List<T> has the .Count property, where as T<> arrays .Length instead. I presume this is because arrays are fixed-length whereas the others aren't, but the difference in syntax can still be frustrating.
If you refactor from an array to list, it therefore gives "does not contain a definition for .Length" errors, and it seems a waste of time having to change it when .Count and .Length are essentially the same.
Is it there a good way to deal with this ? Is it possible to extend List<T> to add an .Length property that's an alias for .Count for instance, and vice-versa for the generic array ? And would this be a bad idea for any reason ?
You can use the Count method provided by LINQ.
This is optimised to use the Count property provided by the ICollection<T> interface where possible (or the non-generic ICollection interface too in .NET 4). So arrays, List<T> etc will all be optimised.
var yourList = new List<string> { "the", "quick", "brown", "fox" };
int count1 = yourList.Count(); // uses the ICollection<T>.Count property
var yourArray = new[] { 1, 2, 4, 8, 16, 32, 64, 128 };
int count2 = yourArray.Count(); // uses the ICollection<T>.Count property
var yourEnumerable = yourArray.Where(x => x > 42);
int count3 = yourEnumerable.Count(); // no optimisation, iterates the sequence
Alternatively, if you wanted a consistent count property of some kind without running the risk of iterating an entire sequence in the non-optimised case then you could create your own extension methods. (I personally wouldn't go down this route.)
int count4 = yourList.GetCount(); // uses the ICollection<T>.Count property
int count5 = yourArray.GetCount(); // uses the ICollection<T>.Count property
int count6 = yourEnumerable.GetCount(); // compile-time error
// ...
public static class CollectionExtensions
{
public static int GetCount<T>(this ICollection<T> source)
{
if (source == null) throw new ArgumentNullException("source");
return source.Count;
}
public static int GetCount(this ICollection source)
{
if (source == null) throw new ArgumentNullException("source");
return source.Count;
}
}
You could put your array in a variable of type IList<T>. (arrays implement this interface)
You can then use the array exactly the way you use any other IList<T> (although Add and Remove will throw exceptions, since arrays are fixed-length)
You can use the .Count() method for both List and Arrays.
The .Count() method runs if it is available, then it falls back to the traditional .Length.
You could simply extend the generic List and add a count method, however if the reason for this is simply because your re-factoring and don't want to update to Count, I don't advise doing so. No need to extend a class if you're not really adding anything to it. Why not just update your code to use Count instead of Length?

List, not lose the reference

Back from interview. I share with you and a good and precise answer is welcome.
The purpose, you have a static method, this method receive an IList<int> you have
to get back the values you can divise by 3 and make the code.
Constraint :
The original list (in the main) has a reference on the stack and the values on the heap,
the result must be return (it's a void method) in the same space (on the heap) than the original list. The solution show here is not correct because in the method a new pointer
on the stack + heap are created in the method domain. Solution ?
Bonus : how change the code to receive not only int but float, double, ....
static void Main(string[] args)
{
IList<int> list = new List<int>() { 9, 3, 10, 6, 14, 16, 20};
CanBeDivedByThree(list);
}
static void CanBeDivedByThree(IList<int> list)
{
list = (from p in list
where p % 3 == 0
orderby p descending
select p).ToList<int>();
}
That's meaningless as the internal storage to an IList is not under your control. Adding (or possibly removing) items might re-allocate the internal data structures.
It is especially meaningless as the list in your sample contains value types which are copied anyway when you access them.
Last but not least it's basically the whole point of using a managed language that you don't have to worry about memory (al)locations. Such things are implementation details of the platform.
To take up on your bonus question: There is no simple way to achieve that. One could think that using generics with a type constraint would solve the problem here (something like static void CanBeDivedByThree<T>(IList<T> list) where T : struct), but the problem is that C# does not (yet?) have support for generic arithmetic. C# doesn't have a modulo operator that can take a generic parameter of type 'T' and 'int'.
list.RemoveAll(n => n % 3 == 0);
or
for (int i = list.Count - 1; i >= 0; --i)
{
if (list[i] % 3 != 0)
list.RemoveAt(i);
}
The first approach works only for List<T>.
One could make it a template method, but remainder operation doesn't make much sense on floats.
Unfortunately only List but not IList does implement RemoveAll. So I first implement it as an extension method.
public static int RemoveAll<T>(this IList<T> list, Predicate<T> match)
{
if (match == null)
throw new ArgumentNullException("match");
int destIndex=0;
int srcIndex;
for(srcIndex=0;srcIndex<list.Count;srcIndex++)
{
if(!match(list[srcIndex]))
{
//if(srcIndex!=destIndex)//Small optimization, can be left out
list[destIndex]=list[srcIndex];
destIndex++;
}
}
for(int removeIndex=list.Count-1;removeIndex>=destIndex;removeIndex--)
{
list.RemoveAt(removeIndex);
}
return srcIndex-destIndex;
}
Then you can use:
list.RemoveAll(n => n % 3 != 0);
You can then use overloads for other types. Unfortunately you can't (easily) make it generic since generics don't work with operator overloading.
Others have covered the list part - this is just for the bonus bit.
You can't do this in a statically typed way using C# generics, but if you're using C# 4 you can do it with dynamic typing. For example:
using System;
using System.Collections.Generic;
class Test
{
static void Main()
{
ShowDivisibleBy3(new List<int> { 1, 3, 6, 7, 9 });
ShowDivisibleBy3(new List<decimal> { 1.5m, 3.3m, 6.0m, 7m, 9.00m });
}
static void ShowDivisibleBy3<T>(IEnumerable<T> source)
{
foreach (dynamic item in source)
{
if (item % 3 == 0)
{
Console.WriteLine(item);
}
}
}
}

Categories