LINQ Using Single with Try..Catch vs First with Count!=1 - c#

What would be the optimal way to get the only element in the list? if it is not equal to one, log it.
Is it better to use a try..catch block against Single? or use Count?
try
{
var item = list.Single();
}
catch(System.InvalidOperationException)
{
//log
Console.WriteLine("The collection does not contain exactly one element.");
}
or
if(list.Count!=1)
{
//log
Console.WriteLine("The collection does not contain exactly one element.");
}
var item = list.FirstOrDefault();

Well, try {...} catch {...} will do stack trace and it means much overhead.
So the 2nd possibility is a better one (Count is a good choice when working with List<T>). Actually, you don't need Linq at all:
// list.Count is just a integer field, a very cheap comparison
if (list.Count != 1) {
// 0 or many items (not a single one)
...
}
else {
// list contains exactly one item
var item = list[0];
...
}
beware traps like this:
List<Object> list = new List<Object>() {
null,
123
};
// item == null even if list has TWO items
var item = list.FirstOrDefault();

if (list == null || list.Count != 1)
{
Console.WriteLine("The collection does not contain exactly one element.");
}
As Iridium commented, Single() or SingleOrDefault() might not be the best choice here because it throws an exception if there is more than one element or the list equals null.
I replaced that with a null-check and a comparison with count

This way is better
if(list.Count!=1)
{
//log
Console.WriteLine("The collection does not contain exactly one element.");
}
var item = list.FirstOrDefault();

Related

What is the most efficient way to find elements in a list that do not exist in another list and vice versa?

Consider you have two lists in C#, first list contains elements of TypeOne and second list contains elements of TypeTwo:
TypeOne
{
int foo;
int bar;
}
TypeTwo
{
int baz;
int qux;
}
Now I need to find elements ( with some property value ) in the first list that don't exist in the second list, and similarly I want to find elements in the second list that don't exist in the first list. (There are only zero or one occurences in either lists.)
What I tried so far is to iterate both lists like this:
foreach (var item in firstList)
{
if (!secondList.Any(a=> a.baz == item.foo)
{
// Item is in the first list but not in second list.
}
}
and again:
foreach (var item in secondList)
{
if (!firstList.Any(a=> a.foo == item.baz)
{
// Item is in the second list but not in first list.
}
}
I hardly think this is a good way to do what I want. I'm iterating my lists two times and use Any in each of them which also iterates the list. So too many iterations.
What is the most efficient way to achieve this?
I am afraid there is no prebuild solution for this, so the best we can do is optimize as much as possible. We only have to iterate the first list, because everything that is in second will be compared already
// First we need copies to operate on
var firstCopy = new List<TypeOne>(firstList);
var secondCopy = new List<TypeTwo>(secondList);
// Now we iterate the first list once complete
foreach (var typeOne in firstList)
{
var match = secondCopy.FirstOrDefault(s => s.baz == typeOne.foo);
if (match == null)
{
// Item in first but not in second
}
else
{
// Match is duplicate and shall be removed from both
firstCopy.Remove(typeOne);
secondCopy.Remove(match);
}
}
After running this both copies will only contain the values which are unique in this instance. This not only reduces it to half the number of iterations but also constantly improves because the second copy shrinks with each match.
Use this LINQ Query.
var result1 = secondList.Where(p2 => !firstList.Any(p1 => p1.foo == p2.baz));
var result2=firstList.Where(p1=> !secondList.Any(p2=> p2.foo == p1.baz);

Remove and Return First Item of List

I was wondering if there was a build in method to remove and return the first item of a list with one method/command.
I used this, which was not pretty
Item currentItem = items.First();
items.RemoveAt(0);
So I could wrote an extension-method:
public static class ListExtensions
{
public static T RemoveAndReturnFirst<T>(this List<T> list)
{
T currentFirst = list.First();
list.RemoveAt(0);
return currentFirst;
}
}
//Example code
Item currentItem = items.RemoveAndReturnFirst();
Is this the best possibility or is there any built-in method?
The list is returned from a nHibernate-Query and therefore it should remain a List<T>.
Most suitable collection for this operation is Queue:
var queue = new Queue<int>();
queue.Enqueue(10); //add first
queue.Enqueue(20); //add to the end
var first = queue.Dequeue(); //removes first and returns it (10)
Queue makes Enqueue and Dequeue operations very fast. But, if you need to search inside queue, or get item by index - it's bad choice. Compare, how many different types of operations do you have and according to this choose the most suitable collection - queue, stack, list or simple array.
Also you can create a Queue from a List:
var list = new List<int>();
var queue = new Queue<int>(list);
There is no built-in method. Your code looks fine to me.
One small thing, I would use the indexer, not the First extension method:
T currentFirst = list[0];
And check your list if there is a Count > 0.
public static T RemoveAndReturnFirst<T>(this List<T> list)
{
if (list == null || list.Count == 0)
{
// Instead of returning the default,
// an exception might be more compliant to the method signature.
return default(T);
}
T currentFirst = list[0];
list.RemoveAt(0);
return currentFirst;
}
If you have to worry about concurrency, I would advice to use another collection type, since this one isn't thread-safe.

Select the particular list from IList

I am using ImageListView dll in windows application, one of my situation I need to select the last index value from IList.
My existing working code
var items = ((flag == 1) ? (IList<ImageListViewItem>)imageListView1.Items : (IList<ImageListViewItem>)imageListView1.SelectedItems);
foreach (ImageListViewItem item in items)
{
...
}
I am trying to select the first value from IList using below code
var items = ((flag == 1) ? (IList<ImageListViewItem>)imageListView1.Items : (IList<ImageListViewItem>)imageListView1.SelectedItems[0]);
foreach (ImageListViewItem item in items)
{
...
}
If i trying by the above code I got the following error
"Additional information: Unable to cast object of type 'Manina.Windows.Forms.ImageListViewItem' to type 'System.Collections.Generic.IList`1"
The problem is you're trying to cast a single ImageListViewItem to an IList<ImageListViewItem>. You need to create a new list containing this item if you want to stick to that contract.
I think the ternary operator and lots of casting is hurting the readability a lot here, so how about a helper method:
private IList<ImageListViewItem> GetItems(int flag)
{
IList<ImageListViewItem> items;
if (flag == 1)
{
items = imageListView1.Items
}
else
{
items = imageListView1.SelectedItems.Take(1).ToList();
}
return items;
}
This will also ensure returning an empty list when there are no items currently selected rather than throwing an exception.
Maybe you want to do something like this:
foreach (ImageListViewItem item in imageListView1.SelectedItems)
{
//Use you item here.
...
//In case flag is raised - break the loop after firs item use.
if(flag == 1)
break;
}

Remove/Add items to/from a list while iterating it

First, I know this isn't possible out of the box because of obvious reasons.
foreach(string item in myListOfStrings) {
myListOfStrings.Remove(item);
}
The snipped above is one of the most horrible things I've ever seen. So, how do you achieve it then? You could iterate through the list backwards using for, but I don't like this solution either.
What I'm wondering is: Is there a method/extensions that returns an IEnumerable from the current list, something like a floating copy? LINQ has numerous extension methods that do exactly this, but you always have to do something with it, such as filtering (where, take...).
I'm looking forward to something like this:
foreach(string item in myListOfStrings.Shadow()) {
myListOfStrings.Remove(item);
}
where as .Shadow() is:
public static IEnumerable<T> Shadow<T>(this IEnumerable<T> source) {
return new IEnumerable<T>(source);
// or return source.Copy()
// or return source.TakeAll();
}
Example
foreach(ResponseFlags flag in responseFlagsList.Shadow()) {
switch(flag) {
case ResponseFlags.Case1:
...
case ResponseFlags.Case2:
...
}
...
this.InvokeSomeVoidEvent(flag)
responseFlagsList.Remove(flag);
}
Solution
This is how I solved it, and it works like a charm:
public static IEnumerable<T> Shadow<T>(this IEnumerable<T> source) where T: new() {
foreach(T item in source)
yield return item;
}
It's not that super fast (obviously), but it's safe and exactly what I intended to do.
Removing multiple elements from a list 1 by 1 is a C# anti-pattern due to how lists are implemented.
Of course, it can be done with a for loop (instead of foreach). Or it can be done by making a copy of the list. But here is why it should not be done. On a list of 100000 random integers, this takes 2500 ms on my machine:
foreach (var x in listA.ToList())
if (x % 2 == 0)
listA.Remove(x);
and this takes 1250 ms:
for (int i = 0; i < listA.Count; i++)
if (listA[i] % 2 == 0)
listA.RemoveAt(i--);
while these two take 5 and 2 ms respectively:
listB = listB.Where(x => x % 2 != 0).ToList();
listB.RemoveAll(x => x % 2 == 0);
This is because when you remove an element from a list, you are actually deleting from an array, and this is O(N) time, as you need to shift each element after the deleted element one position to the left. On average, this will be N/2 elements.
Remove(element) also needs to find the element before removing it. So Remove(element) will actually always take N steps - elementindex steps to find the element, N - elementindex steps to remove it - in total, N steps.
RemoveAt(index) doesn't have to find the element, but it still has to shift the underlying array, so on average, a RemoveAt is N/2 steps.
The end result is O(N^2) complexity either way, as you're removing up to N elements.
Instead, you should use Linq, which will modify the entire list in O(N) time, or roll your own, but you should not use Remove (or RemoveAt) in a loop.
Why not just do:
foreach(string item in myListOfStrings.ToList())
{
myListOfStrings.Remove(item);
}
To create a copy of the original and use for iterating, then remove from the existing.
If you really need your extension method you could perhaps create something more readable to the user such as:
public static IEnumerable<T> Shadow<T>(this IEnumerable<T> items)
{
if (items == null)
throw new NullReferenceException("Items cannot be null");
List<T> list = new List<T>();
foreach (var item in items)
{
list.Add(item);
}
return list;
}
Which is essentially the same as .ToList().
Calling:
foreach(string item in myListOfStrings.Shadow())
You do not LINQ extension methods for this - you can create a new list explicitly, like this:
foreach(string item in new List<string>(myListOfStrings)) {
myListOfStrings.Remove(item);
}
You have to create a copy of the original list while iterating as below:
var myListOfStrings = new List<string>();
myListOfStrings.Add("1");
myListOfStrings.Add("2");
myListOfStrings.Add("3");
myListOfStrings.Add("4");
myListOfStrings.Add("5");
foreach (string item in myListOfStrings.ToList())
{
myListOfStrings.Remove(item);
}
Your example removes all items from the string, so it's equivalent to:
myListOfStrings.Clear();
It is also equivalent to:
myListOfStrings.RemoveAll(x => true); // Empties myListOfStrings
But what I think you're looking for is a way to remove items for which a predicate is true - which is what RemoveAll() does.
So you could write, for example:
myListOfStrings.RemoveAll(x => x == "TEST"); // Modifies myListOfStrings
Or use any other predicate.
However, that changes the ORIGINAL list; If you just want a copy of the list with certain items removed, you can just use normal Linq:
// Note != instead of == as used in Removeall(),
// because the logic here is reversed.
var filteredList = myListOfStrings.Where(x => x != "TEST").ToList();
Picking up on the answer of svinja I do believe the most efficient way of solving this problem is by doing:
for (int i = 0; i < listA.Count;) {
if (listA[i] % 2 == 0)
listA.RemoveAt(i);
else
i++;
}
It improves on the answer by removing unnecessary sums and subtractions.

Should I use Single() or SingleOrDefault() if there is a chance that the element won't be found?

What would you prefer to see?
try
{
var item = list.Single(x => x.HasFoo);
}
catch(InvalidOperationException e)
{
throw new InvalidOperationException("Exactly one item with foo expected, none found", e);
}
Or:
var item = list.SingleOrDefault(x => x.HasFoo);
if (item == null)
throw new InvalidOperationException("Exactly one item with foo expected, none found");
What's the best practice here? Which one makes the exception more comprehensible?
Use SingleOrDefault() if 0 or 1 items are expected
Use Single() if 1, not 0 or 2 and more, item is expected
Also keep in mind that there are a number of possible scenarios:
You got 0 when 0 or 1 was expected (ok)
You got 1 when 0 or 1 was expected (ok)
You got 2 or more when 0 or 1 was expected (error)
And:
You got 0 when 1 was expected (error)
You got 1 when 1 was expected (ok)
You got 2 or more when 1 was expected (error)
And don't forget about First(), FirstOrDefault() and Any()
I would write:
var item = list.Single(x => x.HasFoo);
If the case where this does not return a single item is so common you need a friendlier error message, then is it really an exception at all?
Practically, they are the same. But I prefer second one since one exception is thrown while in the first two. Exceptions are expensive.
I think it's OK to write
var item = list.SingleOrDefault(x => x.HasFoo);
if (item == null) ...
but you can also write
if (list.Any(x => x.HasFoo)) ...
if you don't actually need access to the value.
If you ALWAYS EXPECT  one element in the list, just use 
var item = list.Single(x => x.HasFoo);
and catch exception at the top level method, where you will log details of exception and show friendly message to the user.
If you sometimes expect 0 or more than 1 elements, the safest method will be
var item = list.FirstOrDefault(x => x.HasFoo);
if (item == null)
{ 
// empty list processing, not necessary throwing exception
}
I assumed, that it is not important to verify, are more than 1 record exist or not.
Similar question was discussed in Code Project article LINQ: Single vs. SingleOrDefault
I'd rather see a check to the number of elements in the list before getting the element, rather than waiting for an exception, then throwing a new one.
var listFiltered = list.Where(x => x.HasFoo).ToList();
int listSize = listFiltered.Count();
if (listSize == 0)
{
throw new InvalidOperationException("Exactly one item with foo expected, none found");
}
else if (listSize > 1)
{
throw new InvalidOperationException("Exactly one item with foo expected, more than one found");
}
It's nice that the suggestions are compact, but better to be more explicit IMO.
(Also in your suggestions the exceptions are not strictly valid: they say 'none found' when there could be more than one)
Edit: Jeebus, added one line to filter the list first for pedantic people. (I thought it would have been obvious for anyone)
Assuming you were asking about the 0..1 scenario, I prefer SingleOrDefault because it lets you specify your own way to handle the "nothing found" scenario.
So, a good way to do using a little syntactic sugar, would be:
// assuming list is List<Bar>();
var item = list.SingleOrDefault(x => x.HasFoo) ?? notFound<Bar>();
where notFound() is:
T notFound<T>()
{
throw new InvalidOperationException("Exactly one item with foo expected, none found");
}
I agree with Kieren Johnstone, don't wait for the exception this is pretty costly, sure when you call this method alot of times.
You're first code snippet is even more expensive, because you wait for the original exception, and than throw yourself a new one.
Single
It returns a single specific element from a collection of elements if
element match found. An exception is thrown, if none or more than one
match found for that element in the collection.
SingleOrDefault
It returns a single specific element from a collection of elements if
element match found. An exception is thrown, if more than one match
found for that element in the collection. A default value is returned,
if no match is found for that element in the collection.
here is sample example:-
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LinqSingleorSingleOrDefault
{
class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string City { get; set; }
}
public class Program
{
static void Main(string[] args)
{
IList<Employee> employeeList = new List<Employee>(){
new Employee() { Id = 10, Name = "Chris", City = "London" },
new Employee() { Id=11, Name="Robert", City="London"},
new Employee() { Id=12, Name="Mahesh", City="India"},
new Employee() { Id=13, Name="Peter", City="US"},
new Employee() { Id=14, Name="Chris", City="US"}
};
//Single Example
var result1 = employeeList.Single();
// this will throw an InvalidOperationException exception because more than 1 element in employeeList.
var result2 = employeeList.Single(e => e.Id == 11);
//exactly one element exists for Id=11
var result3 = employeeList.Single(e => e.Name == "Chris");
// throws an InvalidOperationException exception because of more than 1 element contain for Name=Chris
IList<int> intList = new List<int> { 2 };
var result4 = intList.Single();
// return 2 as output because exactly 1 element exists
//SingleOrDefault Example
var result5 = employeeList.SingleOrDefault(e => e.Name == "Mohan");
//return default null because not element found for specific condition.
var result6 = employeeList.SingleOrDefault(e => e.Name == "Chris");
// throws an exception that Sequence contains more than one matching element
var result7 = employeeList.SingleOrDefault(e => e.Id == 12);
//return only 1 element
Console.ReadLine();
}
}
}

Categories

Resources