ICollection - Get single value - c#

What is the best way to get a value from a ICollection?
We know the Collection is empty apart from that.

You can use LINQ for this:.
var foo = myICollection.OfType<YourType>().FirstOrDefault();
// or use a query
var bar = (from x in myICollection.OfType<YourType>() where x.SomeProperty == someValue select x)
.FirstOrDefault();

The simplest way to do this is:
foreach(object o in collection) {
return o;
}
But this isn't particularly efficient if it's actually a generic collection because IEnumerator implements IDisposable, so the compiler has to put in a try/finally, with a Dispose() call in the finally block.
If it's a non-generic collection, or you know the generic collection implements nothing in its Dispose() method, then the following can be used:
IEnumerator en = collection.GetEnumerator();
en.MoveNext();
return en.Current;
If you know if may implement IList, you can do this:
IList iList = collection as IList;
if (iList != null) {
// Implements IList, so can use indexer
return iList[0];
}
// Use the slower way
foreach (object o in collection) {
return o;
}
Likewise, if it's likely it'll be of a certain type of your own definition that has some kind of indexed access, you can use the same technique.

collection.ToArray()[i]
This way is slow, but very simple to use.

Without generics and because ICollection implements IEnumerable you can do like in example 1. With generics you simple need to do like example 2:
List<string> l = new List<string>();
l.Add("astring");
ICollection col1 = (ICollection)l;
ICollection<string> col2 = (ICollection<string>)l;
//example 1
IEnumerator e1 = col1.GetEnumerator();
if (e1.MoveNext())
Console.WriteLine(e1.Current);
//example 2
if (col2.Count != 0)
Console.WriteLine(col2.Single());

If you know your collection has only one item, should only ever have one item, you can use the Linq extension method Single().
This converts a ICollection<T> into a T object containing the single item of that collection. If the length of the collection is 0, or more than one, this will throw an InvalidOperationException.

Related

How Can I Retrieve the Underlying List of an IEnumerable Without Creating a New List?

When using IEnumerable I'm trying to avoid multiple enumerations. I know I can just use LINQ's .ToList() and be done with it, but that can be a lot of unnecessary list creation. I'd like to:
check and see if the underlying type is a List, and if so return that instance, otherwise
.ToList() it and return the new List
My thought was to use something akin to:
public void Fee()
{
var list = new List<string>(); // I want to retrieve this instance in Foo
Foo(list);
}
public void Foo(IEnumerable<T> enumerable)
{
var list = enumerable as List<T> ?? enumerable.ToList();
// do stuff with original list
}
... but it appears from the documentation that the as operator just performs a cast, which would create a new List rather than returning the underlying one, would it not?
If so, how can I retrieve the underlying list instead of creating a new one?
The as operator does not create a new list. It only checks type and perform cast if type is compatible.
The code in the post is logically correct and matches how many LINQ methods are implemented (for example see source of Enumerable.Count which casts to ICollection to see if it can skip enumeration of items).
Note that it is important to cast to correct generic version of list or maybe one of its interfaces - IList would work if you must use non-generic version. Beware of the fact that List<T> is not co/contra-variant and type must match exactly unlike in case of covariant IEnumerable<out T> where you can cast parameter to IEnumerable<TBase> if IEnumerable<TDerived> passed.
Maybe you wanted to do this:
public void Fee()
{
var list = new List<string>(); // I want to retrieve this instance in Foo
Foo(list);
}
public void Foo<T>(IEnumerable<T> enumerable)
{
List<T> list = enumerable as List<T> ?? enumerable.ToList();
// do stuff with original list
}

Check if var is a List of any kind of objects

I'm developing an application with .NET Framework 4.6.1 and C#.
I want to do this:
var val = actionArguments[key];
if (val is List<T> as class)
I want to check if val is a List of any kind of object but that statement doesn't compile.
How can I check if a variable declared as var is a List?
On my application var is List<Code>. Code is a custom class that I made. And List is System.Generic.Collections.
Since List<T> is also implementing the non-generic IList interface, you can simply check
if (val is IList)
That's not to say that one can assume that anything that is IList is neccessarily a List<T>. But, in the case of the OP, that is having some indexer returning an object and needs to differ between specific (perhaps known) types, avoiding GetType() and relying on is IList is good enough for this purpose.
See MSDN
A wordy comparison, but exact one: any List<T> is generic type and have the same generic type definition
if (val.GetType().IsGenericType &&
val.GetType().GetGenericTypeDefinition() == typeof(List<>)) {
...
}
Comparison with IList is not enough, an exotic counter example:
// generic, does implement IList, does not implement IList<T>
public class CounterExample<T>: IList {
...
}
if(val is IList && val.GetType().IsGenericType &&
val.GetType().GetGenericTypeDefinition() == typeof(List<>))
{
}
Be aware you should check if val.GetType() is Generic, only val is IList will return true for ArrayList too.
EDIT:
Like Jeppe Stig Nielsen mention in comments, you should add the check val.GetType().GetGenericTypeDefinition() == typeof(List<>) to the if too.
How about:
var val = actionArguments[key];
var codes = val as List<Code>;
if(codes == null)
{
// val is not of the desired type, so exit, crash, whatever...
return;
}
// work with your list of codes...
foreach(var code in codes)
{
Console.WriteLine(code);
}

Array, List, IEnumerable, CustomList class cast to one and iterate threw them

I am trying to figure out a way that tells me if a certain type is an array/list/ienumerable/collection ... I dont care what kind of it is even CustomLists so something like
FooList<T> : IList<T>
FooList : IList
or stuff like that.
I kinda hoped that a simple type.IsArray would be enough but sadly this isnt the case.
I need a way to check if its one of the above types and then check what the underlying type is, and than cast it to a Indexed based collection, where I can loop through the entries.
For a simple array this is all I need:
if (obj.GetType().IsArray)
{
var elementType = obj.GetType().GetElementType();
if (elementType.IsPrimitive == false)
{
var array = (Array)obj;
}
}
This should work for every collection, there could possible be.
Edit:
As recommended below, I should as/is to IEnumerable but with IEnumerable I have the problem that the I cannot set certain object inside this IEnumerable.
With array I have used the method array.SetValue(obj, index) which works fine.
When I loop threw the IEnumerable and try to set one entry like this:
var list = obj as IEnumarble;
if (list != null)
{
foreach (var item in list)
{
item = new object();
}
}
I am getting the following message:
Readonly local variable cannot be used as an assignment target.
You can try to cast it with the as operator:
var enumerable = list as IEnumerable;
if (enumerable != null)
{
foreach (object item in enumerable)
{
// ...
}
}
However, if you need to modify it you have to recreate it. For example by using a list which you fill in the loop. Then reassign it to the original variable.
Or you could check if the type is a ILIst in the first place (like an array or list), then you can use it`s indexer:
var ilist = list as IList;
if (ilist != null)
{
for (int i = 0; i < ilist.Count; i++)
{
ilist[i] = "new value";
}
}
IIRC, you could do a simple inheritence check for the enumerable interface via
if (FooList is IEnumerable)
// We have a List
You can also use Linq and do a
if (FooList.ToList().Count > 1)
// We have a List
But this would be rather unconventional.

Does IEnumerable always imply a collection?

Just a quick question regarding IEnumerable:
Does IEnumerable always imply a collection? Or is it legitimate/viable/okay/whatever to use on a single object?
The IEnumerable and IEnumerable<T> interfaces suggest a sequence of some kind, but that sequence doesn't need to be a concrete collection.
For example, where's the underlying concrete collection in this case?
foreach (int i in new EndlessRandomSequence().Take(5))
{
Console.WriteLine(i);
}
// ...
public class EndlessRandomSequence : IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
var rng = new Random();
while (true) yield return rng.Next();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
It is always and mandatory that IEnumerable is used on a single object - the single object is always the holder or producer of zero or more other objects that do not necessarily have any relation to IEnumerable.
It's usual, but not mandatory, that IEnumerable represents a collection.
Enumerables can be collections, as well as generators, queries, and even computations.
Generator:
IEnumerable<int> Generate(
int initial,
Func<int, bool> condition,
Func<int, int> iterator)
{
var i = initial;
while (true)
{
yield return i;
i = iterator(i);
if (!condition(i))
{
yield break;
}
}
}
Query:
IEnumerable<Process> GetProcessesWhereNameContains(string text)
{
// Could be web-service or database call too
var processes = System.Diagnostics.Process.GetProcesses();
foreach (var process in processes)
{
if (process.ProcessName.Contains(text))
{
yield return process;
}
}
}
Computation:
IEnumerable<double> Average(IEnumerable<double> values)
{
var sum = 0.0;
var count = 0;
foreach (var value in values)
{
sum += value;
yield return sum/++count;
}
}
LINQ is itself a series of operators that produce objects that implement IEnumerable<T> that don't have any underlying collections.
Good question, BTW!
NB: Any reference to IEnumerable also applies to IEnumerable<T> as the latter inherits the former.
Yes, IEnumerable implies a collection, or possible collection, of items.
The name is derived from enumerate, which means to:
Mention (a number of things) one by one.
Establish the number of.
According to the docs, it exposes the enumerator over a collection.
You can certainly use it on a single object, but this object will then just be exposed as an enumeration containing a single object, i.e. you could have an IEnumerable<int> with a single integer:
IEnumerable<int> items = new[] { 42 };
IEnumerable represents a collection that can be enumerated, not a single item. Look at MSDN; the interface exposes GetEnumerator(), which
...[r]eturns an enumerator that iterates through a collection.
Yes, IEnumerable always implies a collection, that is what enumerate means.
What is your use case for a single object?
I don't see a problem with using it on a single object, but why do want to do this?
I'm not sure whether you mean a "collection" or a .NET "ICollection" but since other people have only mentioned the former I will mention the latter.
http://msdn.microsoft.com/en-us/library/92t2ye13.aspx
By that definition, All ICollections are IEnumerable. But not the other way around.
But most data structure (Array even) just implement both interfaces.
Going on this train of thought: you could have a car depot (a single object) that does not expose an internal data structure, and put IEnumerable on it. I suppose.

How to validate if a collection contains all unique objects

I have a C# collection of objects that do not implement IEquatable or IComparable. I want to check if the collection contains duplicate objects. I.e. I want to know if Object.ReferenceEquals(x, y) is false for any x and y in my list.
How would I do that efficiently?
It would be nice with both a C# and a LINQ method.
Non-LINQ, when your collection implements ICollection<T> or ICollection:
bool allItemsUnique =
new HashSet<YourType>(yourCollection).Count == yourCollection.Count;
Non-LINQ, when your collection doesn't implement ICollection<T> or ICollection. (This version has slightly better theoretical performance than the first because it will break out early as soon as a duplicate is found.)
bool allItemsUnique = true;
var tempSet = new HashSet<YourType>();
foreach (YourType obj in yourCollection)
{
if (!tempSet.Add(obj))
{
allItemsUnique = false;
break;
}
}
LINQ. (This version's best case performance -- when your collection implements ICollection<T> or ICollection -- will be roughly the same as the first non-LINQ solution. If your collection doesn't implement ICollection<T> or ICollection then the LINQ version will be less efficient.)
bool allItemsUnique =
yourCollection.Distinct().Count() == yourCollection.Count();
I would suggest you to use
collection.GroupBy(x=>x).Any(x=>x.Count() != 1)
Profit is: iterating through collection would stop as soon, as first duplicate object would be found.

Categories