For example, I have an IEnumerable<(int, char)> list. How to convert list into (IEnumerable<int>, IEnumerable<char>)?
Is there a fast way to do this? It would be better to work with System.Linq.
It's quite simple with Aggregate:
IEnumerable<(int, char)> list = new[]
{
(1, 'a'), (2, 'b'),
};
(List<int> ints, List<char> chars) =
list.Aggregate((new List<int>(), new List<char>()), (a, x) =>
{
a.Item1.Add(x.Item1);
a.Item2.Add(x.Item2);
return a;
});
That gives:
That's the fastest way, but this is simpler:
List<int> ints = list.Select(x => x.Item1).ToList();
List<char> chars = list.Select(x => x.Item2).ToList();
There are two issues to consider:
You don't want to iterate over the input more than once.
You want to size the returned lists to the correct length when creating them if possible, to avoid multiple list resizing.
To efficiently find the length of an IEnumerable<T> you can use the .NET 6 Enumerable.TryGetNonEnumeratedCount().
Note that of course this will not work for some IEnumerable types, but it will work in many cases.
Also note that for small list sizes, calling Enumerable.TryGetNonEnumeratedCount() will likely make things slower, since a default-sized list would probably already be big enough to prevent resizing.
A method using this would look something like this:
public static (IEnumerable<T>, IEnumerable<U>) Deconstruct<T,U>(IEnumerable<(T,U)> sequence)
{
List<T> listT;
List<U> listU;
if (sequence.TryGetNonEnumeratedCount(out int count))
{
listT = new List<T>(count);
listU = new List<U>(count);
}
else
{
listT = new List<T>();
listU = new List<U>();
}
foreach (var item in sequence)
{
listT.Add(item.Item1);
listU.Add(item.Item2);
}
return (listT, listU);
}
This code isn't very elegant because there's no short way of writing the code to initialise the lists to the correct size. But it is probably about as efficient as you are likely to get.
You could possibly make it slightly more performant by returning arrays rather than lists if you know the count:
public static (IEnumerable<T>, IEnumerable<U>) Deconstruct<T,U>(IEnumerable<(T,U)> sequence)
{
if (sequence.TryGetNonEnumeratedCount(out int count))
{
var arrayT = new T[count];
var arrayU = new U[count];
int i = 0;
foreach (var item in sequence)
{
arrayT[i] = item.Item1;
arrayU[i] = item.Item2;
++i;
}
return (arrayT, arrayU);
}
else
{
var listT = new List<T>();
var listU = new List<U>();
foreach (var item in sequence)
{
listT.Add(item.Item1);
listU.Add(item.Item2);
}
return (listT, listU);
}
}
I would only go to such lengths if performance testing indicated that it's worth it!
If the original is a materialized collection like List<(int, char)> or (int, char)[] you can do the following:
var result = (list.Select(i => i.Item1), list.Select(i => i.Item2));
If the original is just an IEnumerable<(int, char)>, you should convert it to a List first (otherwise the source will get enumerated twice):
var list = source.ToList();
There are cases where this (and all other answers up to now):
does not work at all: when the source is an infinite sequence
or is inefficient: if the source sequence is big, but you intend to enumerate only a few elements of each of the result enumerables
If this is of no concern for the use case given, stop reading here.
It is possible to overcome this restriction with some implementation effort. Basically, the "derived enumerables" have to be implemented in a way that they request just the required items from the source enumerable and no more.
The following solution uses a class TupleEnumerable to fetch only the required elements from the the source and remembering the fetched elements for use by the two derived enumerables.
public class TupleEnumerable<T1, T2> : IDisposable
{
readonly IEnumerator<(T1, T2)> _source;
readonly List<(T1, T2)> _preFetched = new();
private bool _finished;
public TupleEnumerable(IEnumerable<(T1, T2)> source)
{
_source = source.GetEnumerator();
}
public void Dispose()
{
_source.Dispose();
_preFetched.Clear();
_finished = true;
}
// Try to get the element if it already has been fetched
// or otherwise use the source enumerator to fetch more.
private bool TryGet(int index, out (T1, T2) tuple)
{
if (index < _preFetched.Count)
{
tuple = _preFetched[index];
return true;
}
if (_finished)
{
tuple = default;
return false;
}
_finished = !_source.MoveNext();
if (_finished)
{
Console.WriteLine("**Source finished");
tuple = default;
return false;
}
Console.WriteLine($"**Source: {_source.Current}");
_preFetched.Add(_source.Current);
tuple = _source.Current;
return true;
}
// This method returns a tuple of "derived" enumerables
public (IEnumerable<T1>, IEnumerable<T2>) GetEnumerables()
=> (new ProjectedEnumerable<T1>(this, t => t.Item1),
new ProjectedEnumerable<T2>(this, t => t.Item2));
// This is our own implementation of IEnumerator<T>
class ProjectedEnumerable<T> : IEnumerable<T>
{
private readonly TupleEnumerable<T1, T2> _tupleEnumerable;
private readonly Func<(T1, T2), T> _projection;
public ProjectedEnumerable(TupleEnumerable<T1, T2> tupleEnumerable, Func<(T1, T2), T> projection)
{
_tupleEnumerable = tupleEnumerable;
_projection = projection;
}
public IEnumerator<T> GetEnumerator()
{
return new ProjectedEnumerator<T>(_tupleEnumerable, _projection);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
// This is our own implementation of IEnumerable<T>
class ProjectedEnumerator<T> : IEnumerator<T>
{
private readonly TupleEnumerable<T1, T2> _tupleEnumerable;
private readonly Func<(T1, T2), T> _projection;
private int _index;
private T _current;
public ProjectedEnumerator(TupleEnumerable<T1, T2> tupleEnumerable, Func<(T1, T2), T> projection)
{
_tupleEnumerable = tupleEnumerable;
_projection = projection;
}
public bool MoveNext()
{
if (_tupleEnumerable.TryGet(_index, out var current))
{
_current = _projection(current);
_index++;
return true;
}
else
{
_current = default;
return false;
}
}
public void Reset()
{
_index = 0;
_current = default;
}
public T Current => _current;
object IEnumerator.Current => Current;
public void Dispose()
{
}
}
}
Usage:
IEnumerable<(int, char)> list = new[]
{
(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')
};
using var c = new TupleEnumerable<int, char>(list);
var (enumerable1, enumerable2) = c.GetEnumerables();
Note: As Theodor Zoulia pointed out in the comments: the semantics of the TupleEnumerable<T1, T2> is different from a standard enumerable. Enumerating a TupleEnumerable<T1, T2> any number of times, will result in a single enumeration of the underlying source. It effectively doubles as a memoizer.
Related
I have the following method which determines which cars I need to delete from the DB.
private List<CarDTO> BuildCarsToDelete(IList<CarDTO> newCars, IList<CarDTO> existingCars)
{
var missingCars = new List<CarDTO>();
var cars = newCars.Select(c => c.CarId);
var newCarIds = new HashSet<int>(cars);
foreach (var car in existingCars)
{
//If there are no new cars then it had some and they have been removed
if (newCars.Count() == 0)
{
missingCars.Add(car);
}
else
{
if (!newCarIds.Contains(car.CarId))
{
missingCars.Add(car);
}
}
}
return missingCars;
}
This works as I want - but if I want to achieve the same functionality for Customers or Apartments of other DTOs I will be copying a pasting the code but only changing the variable names and the Type of DTO around - is there a nicer way possible using generics which would keep the algorithm and logic as it is but allow me to use on any DTO?
If all the ids are of type int then you can do that by passing in a Func to determine the id.
private List<T> BuildToDelete<T>(
IList<T> newItems,
IList<T> existingItems,
Func<T, int> getId)
{
var missingItems = new List<T>();
var items = newItems.Select(getId);
var newItemIds = new HashSet<int>(items);
foreach (var item in existingItems)
{
if (newItems.Count() == 0)
{
missingItems.Add(item);
}
else
{
if (!newItemIds.Contains(getId(item)))
{
missingItems.Add(item);
}
}
}
return missingItems;
}
Then call as shown below:
var results = BuildToDelete(newCars, existingCars, c => c.CarId);
Assuming you use the interface approach mentioned in comments, a generic version could look something like this:
private List<TEntity> BuildEntitiesToDelete(IList<TEntity> newEntities, IList<TEntity> existingEntities) where TEntity : IEntityWithId
{
var missingEntities = new List<TEntity>();
var entities = newEntities.Select(e => e.Id);
var newEntityIds = new HashSet<int>(entities);
foreach (var entity in existingEntities)
{
if (entities.Count() == 0)
{
missingEntities.Add(entity);
}
else
{
if (!newEntityIds.Contains(entity.Id))
{
missingEntities.Add(entity);
}
}
}
return missingEntities;
}
IEntityWithId is probably a poor name for the interface, but I'll leave picking a better name up to you.
Try something cleaner:
1) create flexible equality comparer (need to add some null checking etc.)
public class FuncEqualityComparer<T> : IEqualityComparer<T>
{
Func<T, T, bool> comparer;
Func<T, int> hash;
public FuncEqualityComparer (Func<T, T, bool> comparer, Func<T, int> hash)
{
this.comparer = comparer;
this.hash = hash;
}
public bool Equals (T x, T y) => comparer (x, y);
public int GetHashCode (T obj) => hash (obj);
}
2) and now, just simply:
var carComparerByID = new FuncEqualityComparer<CarDTO> ((a, b) => a.CarId == b.CarId, x => x.CarId.GetHashCode ());
var result = existingCars.Except (newCars, carComparerByID).ToList ();
When I want to make a value type read-only outside of my class I do this:
public class myClassInt
{
private int m_i;
public int i {
get { return m_i; }
}
public myClassInt(int i)
{
m_i = i;
}
}
What can I do to make a List<T> type readonly (so they can't add/remove elements to/from it) outside of my class? Now I just declare it public:
public class myClassList
{
public List<int> li;
public myClassList()
{
li = new List<int>();
li.Add(1);
li.Add(2);
li.Add(3);
}
}
You can expose it AsReadOnly. That is, return a read-only IList<T> wrapper. For example ...
public ReadOnlyCollection<int> List
{
get { return _lst.AsReadOnly(); }
}
Just returning an IEnumerable<T> is not sufficient. For example ...
void Main()
{
var el = new ExposeList();
var lst = el.ListEnumerator;
var oops = (IList<int>)lst;
oops.Add( 4 ); // mutates list
var rol = el.ReadOnly;
var oops2 = (IList<int>)rol;
oops2.Add( 5 ); // raises exception
}
class ExposeList
{
private List<int> _lst = new List<int>() { 1, 2, 3 };
public IEnumerable<int> ListEnumerator
{
get { return _lst; }
}
public ReadOnlyCollection<int> ReadOnly
{
get { return _lst.AsReadOnly(); }
}
}
Steve's answer also has a clever way to avoid the cast.
There is limited value in attempting to hide information to such an extent. The type of the property should tell users what they're allowed to do with it. If a user decides they want to abuse your API, they will find a way. Blocking them from casting doesn't stop them:
public static class Circumventions
{
public static IList<T> AsWritable<T>(this IEnumerable<T> source)
{
return source.GetType()
.GetFields(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance)
.Select(f => f.GetValue(source))
.OfType<IList<T>>()
.First();
}
}
With that one method, we can circumvent the three answers given on this question so far:
List<int> a = new List<int> {1, 2, 3, 4, 5};
IList<int> b = a.AsReadOnly(); // block modification...
IList<int> c = b.AsWritable(); // ... but unblock it again
c.Add(6);
Debug.Assert(a.Count == 6); // we've modified the original
IEnumerable<int> d = a.Select(x => x); // okay, try this...
IList<int> e = d.AsWritable(); // no, can still get round it
e.Add(7);
Debug.Assert(a.Count == 7); // modified original again
Also:
public static class AlexeyR
{
public static IEnumerable<T> AsReallyReadOnly<T>(this IEnumerable<T> source)
{
foreach (T t in source) yield return t;
}
}
IEnumerable<int> f = a.AsReallyReadOnly(); // really?
IList<int> g = f.AsWritable(); // apparently not!
g.Add(8);
Debug.Assert(a.Count == 8); // modified original again
To reiterate... this kind of "arms race" can go on for as long as you like!
The only way to stop this is to completely break the link with the source list, which means you have to make a complete copy of the original list. This is what the BCL does when it returns arrays. The downside of this is that you are imposing a potentially large cost on 99.9% of your users every time they want readonly access to some data, because you are worried about the hackery of 00.1% of users.
Or you could just refuse to support uses of your API that circumvent the static type system.
If you want a property to return a read-only list with random access, return something that implements:
public interface IReadOnlyList<T> : IEnumerable<T>
{
int Count { get; }
T this[int index] { get; }
}
If (as is much more common) it only needs to be enumerable sequentially, just return IEnumerable:
public class MyClassList
{
private List<int> li = new List<int> { 1, 2, 3 };
public IEnumerable<int> MyList
{
get { return li; }
}
}
UPDATE Since I wrote this answer, C# 4.0 came out, so the above IReadOnlyList interface can take advantage of covariance:
public interface IReadOnlyList<out T>
And now .NET 4.5 has arrived and it has... guess what...
IReadOnlyList interface
So if you want to create a self-documenting API with a property that holds a read-only list, the answer is in the framework.
JP's answer regarding returning IEnumerable<int> is correct (you can down-cast to a list), but here is a technique that prevents the down-cast.
class ExposeList
{
private List<int> _lst = new List<int>() { 1, 2, 3 };
public IEnumerable<int> ListEnumerator
{
get { return _lst.Select(x => x); } // Identity transformation.
}
public ReadOnlyCollection<int> ReadOnly
{
get { return _lst.AsReadOnly(); }
}
}
The identity transformation during enumeration effectively creates a compiler-generated iterator - a new type which is not related to _lst in any way.
Eric Lippert has a series of articles on Immutability In C# on his blog.
The first article in the series can be found here.
You might also find useful Jon Skeet's answer to a similar question.
public List<int> li;
Don't declare public fields, it's generally considered bad practice... wrap it in a property instead.
You can expose your collection as a ReadOnlyCollection :
private List<int> li;
public ReadOnlyCollection<int> List
{
get { return li.AsReadOnly(); }
}
public class MyClassList
{
private List<int> _lst = new List<int>() { 1, 2, 3 };
public IEnumerable<int> ListEnumerator
{
get { return _lst.AsReadOnly(); }
}
}
To check it
MyClassList myClassList = new MyClassList();
var lst= (IList<int>)myClassList.ListEnumerator ;
lst.Add(4); //At this point ypu will get exception Collection is read-only.
public static IEnumerable<T> AsReallyReadOnly<T>(this IEnumerable<T> source)
{
foreach (T t in source) yield return t;
}
if I add to Earwicker's example
...
IEnumerable<int> f = a.AsReallyReadOnly();
IList<int> g = f.AsWritable(); // finally can't get around it
g.Add(8);
Debug.Assert(a.Count == 78);
I get InvalidOperationException: Sequence contains no matching element.
I have written a generic sort funciton to sort list and dicitonary. But LINQ doesnt works on Unity due to JIT errors. I want to have the same generics and convert it into myList.Sort() which uses CompraeTo. But Im unable to figure out how to accomplish this as generic as this.
public static List<T> MySort<T>(this List<T> source, Type typeOfObject, bool isAscending = false, params string[] param)
{
if(param.Length == 0)
return source;
if (isAscending)
{
var temp = source.OrderBy (a => (typeOfObject.GetProperty (param [0])).GetValue (a, null));
for (int i=1; i<param.Length; i++)
{
var myVar = i;
temp = temp.ThenBy((a => (typeOfObject.GetProperty(param[myVar])).GetValue (a, null)));
}
return temp.ToList();
}
else
{
var temp = source.OrderByDescending (a => (typeOfObject.GetProperty (param [0])).GetValue (a, null));
for (int i=1; i<param.Length; i++)
{
var myVar = i;
temp.ThenByDescending((a => (typeOfObject.GetProperty(param[myVar])).GetValue (a, null)));
}
return temp.ToList();
}
}
USage of this function
RealEstateItems.MySort(typeof(mIsoObjectExt), true, "UnlockLevel", "Coins", "Diamonds");
My current CompareTo Approac
myList.Sort ((a,b) => {
int result = ((a.Value) as mIsoObjectExt).UnlockLevel.CompareTo(((b.Value) as mIsoObjectExt).UnlockLevel);
// result == 0 ? result = a.Value.Coins.CompareTo(a.Value.Coins);
if(result == 0)
{
result = ((a.Value) as mIsoObjectExt).Coins.CompareTo(((b.Value) as mIsoObjectExt).Coins);
}
else
{
return result;
}
if(result == 0)
{
return ((a.Value) as mIsoObjectExt).Diamonds.CompareTo(((b.Value) as mIsoObjectExt).Diamonds);
}
return result;
});
But Im not satisfied with this i have to do this every time i have to sort even on the same properties. Basically i want to make something like above that i tell the function the type its properties to sort on and it sorts. How can i do this with Compare/CompareTo?
So we're going to need a few different building blocks to begin with. First off, what you're really doing here is sorting each item on a collection of values, as is seen in this other question. We can pull the solution from there to have a comparer for sorting items based on a collection of values:
public class SequenceComparer<T> : IComparer<IEnumerable<T>>
{
private IComparer<T> comparer;
public SequenceComparer(IComparer<T> compareer = null)
{
this.comparer = comparer ?? Comparer<T>.Default;
}
public int Compare(IEnumerable<T> x, IEnumerable<T> y)
{
using (var first = x.GetEnumerator())
using (var second = x.GetEnumerator())
{
while (true)
{
var firstHasMore = first.MoveNext();
var secondHasMore = second.MoveNext();
if (!firstHasMore && !secondHasMore)
return 0;
var lengthComparison = firstHasMore.CompareTo(secondHasMore);
if (lengthComparison != 0)
return lengthComparison;
var nextComparison = comparer.Compare(first.Current, second.Current);
if (nextComparison != 0)
return nextComparison;
}
}
}
}
We also want a way of creating a Comparison<T> delegate (which List.Sort accepts) from a projection delegate. This method is simple enough to write:
public static Comparison<T> CreateComparison<T, TKey>(Func<T, TKey> selector,
IComparer<TKey> comparer = null)
{
comparer = comparer ?? Comparer<TKey>.Default;
return (a, b) => comparer.Compare(selector(a), selector(b));
}
It'll also be useful for us to be able to reverse a Comparison<T> (to handle descending ordering):
public static Comparison<T> Reverse<T>(this Comparison<T> comparison)
{
return (a, b) => comparison(b, a);
}
Now to pull all of the pieces together. We can create a comparison that, for the projection, projects each item into a sequence of values that represent fetching each of the property names from the item using reflection. We can then reverse the comparer if we need a descending sort.
public static void MySort<T>(this List<T> source,
bool isAscending = false,
params string[] properties)
{
var type = typeof(T);
var comparison = CreateComparison((T item) =>
properties.Select(prop => type.GetProperty(prop).GetValue(item)),
new SequenceComparer<object>());
if (!isAscending)
comparison = comparison.Reverse();
source.Sort(comparison);
}
Note that if you can also use the sequence comparer to simplify the LINQ approach:
public static IEnumerable<T> MyOrdering<T>(this IEnumerable<T> source,
bool isAscending = false,
params string[] properties)
{
var type = typeof(T);
Func<T, IEnumerable<object>> selector = item =>
properties.Select(prop => type.GetProperty(prop).GetValue(item))
.ToList();
if (isAscending)
return source.OrderBy(selector, new SequenceComparer<object>());
else
return source.OrderByDescending(selector, new SequenceComparer<object>());
}
You can use Servy's approach with reflection. If you decide against reflection, you can use the below approach, but it still needs the comparison to be provided from the caller.
public class MultiValueComparer<T> : IComparer<T>
{
private IEnumerable<Comparison<T>> _comparisons;
public MultiValueComparer(IEnumerable<Comparison<T>> comparisons)
{
_comparisons = comparisons;
}
public int Compare(T x, T y)
{
foreach (var comparison in _comparisons)
{
var result = comparison(x, y);
if (result != 0)
return result;
}
return 0;
}
}
An extension method which takes a variable number of parameters
public static void Sort<T>(List<T> source, params Comparison<T>[] comparisons)
{
if (comparisons.Count() == 0)
return;
source.Sort(new MultiValueComparer<T>(comparisons));
}
Usage:
Ascending Order:
Sort(samples, (x, y) => x.Name.CompareTo(y.Name), (x, y) => x.Test.CompareTo(y.Test));
Descending Order:
Sort(samples, (x, y) => y.Name.CompareTo(x.Name), (x, y) => y.Test.CompareTo(x.Test));
I have two lists, I need to find the items in the first list that are missing from the second, but I can only compare them with a Boolean function.
class A
{
internal bool Matching(A a)
{
return true;
}
}
class OuterMatch
{
List<A> List1 = new List<A>();
List<A> List2 = new List<A>();
void BasicOuterJoin()
{
// textbook example of an outer join, but it does not use my Matching function
var missingFrom2 = from one in List1
join two in List2
on one equals two into matching
from match in matching.DefaultIfEmpty()
where match == null
select one;
}
void Matching()
{
// simple use of the matching function, but this is an inner join.
var matching = from one in List1
from two in List2
where one.Matching(two)
select one;
}
void MissingBasedOnMatching()
{
// a reasonable substitute for what I'm after
var missingFrom2 = from one in List1
where (from two in List2
where two.Matching(one)
select two)
.Count() == 0
select one;
}
MissingBasedOnMatching gives me the right results, but it's not visually obviously an outer join like BasicOuterJoin is. Is there a clearer way to do this?
There's a form of GroupJoin that takes a comparison operator, but I'm not clear if there is a way to use it to make an outer join.
I've been using some useful (and short!) code from a blog by Ed Khoze.
He's posted a handy class which provides an adapter so that you can use Enumerable.Except() with a lambda.
Once you have that code, you can use Except() to solve your problem like so:
var missing = list1.Except(list2, (a, b) => a.Matching(b));
Here's a complete compilable sample. Credit to Ed Khoze for the LINQHelper class:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo
{
class A
{
public int Value;
public bool Matching(A a)
{
return a.Value == Value;
}
public override string ToString()
{
return Value.ToString();
}
}
class Program
{
void test()
{
var list1 = new List<A>();
var list2 = new List<A>();
for (int i = 0; i < 20; ++i) list1.Add(new A {Value = i});
for (int i = 4; i < 16; ++i) list2.Add(new A {Value = i});
var missing = list1.Except(list2, (a, b) => a.Matching(b));
missing.Print(); // Prints 0 1 2 3 16 17 18 19
}
static void Main()
{
new Program().test();
}
}
static class MyEnumerableExt
{
public static void Print<T>(this IEnumerable<T> sequence)
{
foreach (var item in sequence)
Console.WriteLine(item);
}
}
public static class LINQHelper
{
private class LambdaComparer<T>: IEqualityComparer<T>
{
private readonly Func<T, T, bool> _lambdaComparer;
private readonly Func<T, int> _lambdaHash;
public LambdaComparer(Func<T, T, bool> lambdaComparer) :
this(lambdaComparer, o => 0)
{
}
private LambdaComparer(Func<T, T, bool> lambdaComparer, Func<T, int> lambdaHash)
{
if (lambdaComparer == null)
throw new ArgumentNullException("lambdaComparer");
if (lambdaHash == null)
throw new ArgumentNullException("lambdaHash");
_lambdaComparer = lambdaComparer;
_lambdaHash = lambdaHash;
}
public bool Equals(T x, T y)
{
return _lambdaComparer(x, y);
}
public int GetHashCode(T obj)
{
return _lambdaHash(obj);
}
}
public static IEnumerable<TSource> Except<TSource>
(
this IEnumerable<TSource> enumerable,
IEnumerable<TSource> second,
Func<TSource, TSource, bool> comparer
)
{
return enumerable.Except(second, new LambdaComparer<TSource>(comparer));
}
}
}
If your problem statement is actually
Find all members of X that do not exist in Y
And given a class Foo that implements IEquatable<Foo> (pretty much what your Matching method does):
class Foo : IEquatable<Foo>
{
public bool Equals( Foo other )
{
throw new NotImplementedException();
}
}
Then this code should give you what you want:
List<Foo> x = GetFirstList() ;
List<Foo> y = GetSecondList() ;
List<Foo> xNotInY = x.Where( xItem => ! y.Any( yItem => xItem.Equals(yItem) ) ).ToList() ;
You should bear in mind that this runs in O(N2) time. Consequently, you might want to implement an IEqualityComparer<Foo> and put your second list in a HashSet<Foo>:
class FooComparer : IEqualityComparer<Foo>
{
public bool Equals(Foo x, Foo y)
{
if ( x == null )
{
return y == null ;
}
else if ( y == null ) return false ;
else
{
return x.Equals(y) ;
}
}
public int GetHashCode(Foo obj)
{
return obj.GetHashCode() ;
}
}
Then do something like
List<Foo> x = GetFirstList() ;
List<Foo> y = GetSecondList() ;
HashSet<Foo> yLookup = new HashSet<Foo>( y , new FooComparer() ) ;
List<Foo> xNotInY = x.Where( x => !yLookup.Contains(x) ) ;
You'll incur some overhead in constructing the hash set (1 pass through the second list), but subsequent lookups via Contains() are O(1).
If you look at the sources for the Linq join operation, this is close to what it does.
It wouldn't be difficult to strip the Linq sources for Join() and it's helpers and tweak them to product left and right join operators instead of the stock inner join.
Does this work for your purposes?
var missing = List1.Except(List2);
If you need custom comparison logic you can build a custom IEqualityComparer. Note however that Except treats both lists as sets, so it will eliminate duplicates from List1.
I wrote this:
public static class EnumerableExtensions
{
public static int IndexOf<T>(this IEnumerable<T> obj, T value)
{
return obj
.Select((a, i) => (a.Equals(value)) ? i : -1)
.Max();
}
public static int IndexOf<T>(this IEnumerable<T> obj, T value
, IEqualityComparer<T> comparer)
{
return obj
.Select((a, i) => (comparer.Equals(a, value)) ? i : -1)
.Max();
}
}
But I don't know if it already exists, does it?
I'd question the wisdom, but perhaps:
source.TakeWhile(x => x != value).Count();
(using EqualityComparer<T>.Default to emulate != if needed) - but you need to watch to return -1 if not found... so perhaps just do it the long way
public static int IndexOf<T>(this IEnumerable<T> source, T value)
{
int index = 0;
var comparer = EqualityComparer<T>.Default; // or pass in as a parameter
foreach (T item in source)
{
if (comparer.Equals(item, value)) return index;
index++;
}
return -1;
}
The whole point of getting things out as IEnumerable is so you can lazily iterate over the contents. As such, there isn't really a concept of an index. What you are doing really doesn't make a lot of sense for an IEnumerable. If you need something that supports access by index, put it in an actual list or collection.
I would implement it like this:
public static class EnumerableExtensions
{
public static int IndexOf<T>(this IEnumerable<T> obj, T value)
{
return obj.IndexOf(value, null);
}
public static int IndexOf<T>(this IEnumerable<T> obj, T value, IEqualityComparer<T> comparer)
{
comparer = comparer ?? EqualityComparer<T>.Default;
var found = obj
.Select((a, i) => new { a, i })
.FirstOrDefault(x => comparer.Equals(x.a, value));
return found == null ? -1 : found.i;
}
}
The way I'm currently doing this is a bit shorter than those already suggested and as far as I can tell gives the desired result:
var index = haystack.ToList().IndexOf(needle);
It's a bit clunky, but it does the job and is fairly concise.
I think the best option is to implement like this:
public static int IndexOf<T>(this IEnumerable<T> enumerable, T element, IEqualityComparer<T> comparer = null)
{
int i = 0;
comparer = comparer ?? EqualityComparer<T>.Default;
foreach (var currentElement in enumerable)
{
if (comparer.Equals(currentElement, element))
{
return i;
}
i++;
}
return -1;
}
It will also not create the anonymous object
The best way to catch the position is by FindIndex This function is available only for List<>
Example
int id = listMyObject.FindIndex(x => x.Id == 15);
If you have enumerator or array use this way
int id = myEnumerator.ToList().FindIndex(x => x.Id == 15);
or
int id = myArray.ToList().FindIndex(x => x.Id == 15);
A bit late in the game, i know... but this is what i recently did. It is slightly different than yours, but allows the programmer to dictate what the equality operation needs to be (predicate). Which i find very useful when dealing with different types, since i then have a generic way of doing it regardless of object type and <T> built in equality operator.
It also has a very very small memory footprint, and is very, very fast/efficient... if you care about that.
At worse, you'll just add this to your list of extensions.
Anyway... here it is.
public static int IndexOf<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
int retval = -1;
var enumerator = source.GetEnumerator();
while (enumerator.MoveNext())
{
retval += 1;
if (predicate(enumerator.Current))
{
IDisposable disposable = enumerator as System.IDisposable;
if (disposable != null) disposable.Dispose();
return retval;
}
}
IDisposable disposable = enumerator as System.IDisposable;
if (disposable != null) disposable.Dispose();
return -1;
}
Hopefully this helps someone.
A few years later, but this uses Linq, returns -1 if not found, doesn't create extra objects, and should short-circuit when found [as opposed to iterating over the entire IEnumerable]:
public static int IndexOf<T>(this IEnumerable<T> list, T item)
{
return list.Select((x, index) => EqualityComparer<T>.Default.Equals(item, x)
? index
: -1)
.FirstOr(x => x != -1, -1);
}
Where 'FirstOr' is:
public static T FirstOr<T>(this IEnumerable<T> source, T alternate)
{
return source.DefaultIfEmpty(alternate)
.First();
}
public static T FirstOr<T>(this IEnumerable<T> source, Func<T, bool> predicate, T alternate)
{
return source.Where(predicate)
.FirstOr(alternate);
}
Stumbled across this today in a search for answers and I thought I'd add my version to the list (No pun intended). It utlises the null conditional operator of c#6.0
IEnumerable<Item> collection = GetTheCollection();
var index = collection
.Select((item,idx) => new { Item = item, Index = idx })
//or .FirstOrDefault(_ => _.Item.Prop == something)
.FirstOrDefault(_ => _.Item == itemToFind)?.Index ?? -1;
I've done some 'racing of the old horses' (testing) and for large collections (~100,000), worst case scenario that item you want is at the end, this is 2x faster than doing ToList().FindIndex(). If the Item you want is in the middle its ~4x faster.
For smaller collections (~10,000) it seems to be only marginally faster
Heres how I tested it https://gist.github.com/insulind/16310945247fcf13ba186a45734f254e
An alternative to finding the index after the fact is to wrap the Enumerable, somewhat similar to using the Linq GroupBy() method.
public static class IndexedEnumerable
{
public static IndexedEnumerable<T> ToIndexed<T>(this IEnumerable<T> items)
{
return IndexedEnumerable<T>.Create(items);
}
}
public class IndexedEnumerable<T> : IEnumerable<IndexedEnumerable<T>.IndexedItem>
{
private readonly IEnumerable<IndexedItem> _items;
public IndexedEnumerable(IEnumerable<IndexedItem> items)
{
_items = items;
}
public class IndexedItem
{
public IndexedItem(int index, T value)
{
Index = index;
Value = value;
}
public T Value { get; private set; }
public int Index { get; private set; }
}
public static IndexedEnumerable<T> Create(IEnumerable<T> items)
{
return new IndexedEnumerable<T>(items.Select((item, index) => new IndexedItem(index, item)));
}
public IEnumerator<IndexedItem> GetEnumerator()
{
return _items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Which gives a use case of:
var items = new[] {1, 2, 3};
var indexedItems = items.ToIndexed();
foreach (var item in indexedItems)
{
Console.WriteLine("items[{0}] = {1}", item.Index, item.Value);
}
This can get really cool with an extension (functioning as a proxy), for example:
collection.SelectWithIndex();
// vs.
collection.Select((item, index) => item);
Which will automagically assign indexes to the collection accessible via this Index property.
Interface:
public interface IIndexable
{
int Index { get; set; }
}
Custom extension (probably most useful for working with EF and DbContext):
public static class EnumerableXtensions
{
public static IEnumerable<TModel> SelectWithIndex<TModel>(
this IEnumerable<TModel> collection) where TModel : class, IIndexable
{
return collection.Select((item, index) =>
{
item.Index = index;
return item;
});
}
}
public class SomeModelDTO : IIndexable
{
public Guid Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public int Index { get; set; }
}
// In a method
var items = from a in db.SomeTable
where a.Id == someValue
select new SomeModelDTO
{
Id = a.Id,
Name = a.Name,
Price = a.Price
};
return items.SelectWithIndex()
.OrderBy(m => m.Name)
.Skip(pageStart)
.Take(pageSize)
.ToList();
Try this:
static int FindIndex<T>(this IEnumerable<T> a, Predicate<T> f) =>
a.TakeWhile(x => !f(x)).Count();
static int IndexOf<T>(this IEnumerable<T> a, T value) =>
a.FindIndex(x => EqualityComparer<T>.Default.Equals(x, value));
var i = new[] { 1, 2, 3 }.IndexOf(2); // 1