Convert a generic IEnumerable<T> to IEnumerable<KeyValuePair> (C#) - c#

In the following code, I need to explicitly mention CountryId and CountryName but I would like to avoid that and trying to create a generic method.
public struct KeyValueStruct
{
public int Key { get; set; }
public string Value { get; set; }
}
private static IEnumerable<KeyValueStruct> ConvertPocoToKeyValueList(IEnumerable<CountryPoco> list)
{
var result = new List<KeyValueStruct>();
if (list != null)
{
foreach (var item in list)
{
result.Add(new KeyValueStruct()
{
Key = item.CountryId,
Value = item.CountryName
});
}
}
return result;
}
I know from the list that first property is always integer (which is CountryId in this example) and second property would be String.
I was thinking to implement using Generics but am not sure is this the best approach, see my proposed code (it's not working though).
private static IEnumerable<KeyValueStruct> ConvertPocoToKeyValueList<T>(T list)
{
var result = new List<KeyValueStruct>();
if (list != null)
{
foreach (var item in list)
{
result.Add(new KeyValueStruct()
{
Key = item.CountryId,
Value = item.CountryName
});
}
}
return result;
}
If you have a better idea to achieve the same result, then please propose.

You can make that generic by passing the properties to be used as Key and value. I think using the generic struct named KeyValuePair<Tkey, TValue> is better than reinventing the wheel yourself:
private static IEnumerable<KeyValuePair<Tkey, TValue>>
ConvertPocoToKeyValueList<TSource, Tkey, TValue>
(IEnumerable<TSource> list,
Func<TSource, Tkey> keySelector,
Func<TSource, TValue> valueSelector)
{
return list.Select(item => new KeyValuePair<Tkey, TValue>
(keySelector(item), valueSelector(item)));
}
Usage:
var result = ConvertPocoToKeyValueList(list, x=> x.CountryId, x=> x.CountryName);
You can even do that without using this generic method by using directly:
var result = list.Select(item => new KeyValuePair<Tkey, TValue>
(item.CountryId, item.CountryName));

Related

Write similar logic using generics

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 ();

C# - Convert IEnumerable to Dictionary<object,string>

I am building a WPF UserControl. For this I implemented an ItemSource DependecyProperty like this:
private IEnumerable MisItems;
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(TextBoxAutoComplete), new PropertyMetadata(new PropertyChangedCallback(OnItemsSourcePropertyChanged)));
private static void OnItemsSourcePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var control = sender as TextBoxAutoComplete;
if (control != null)
control.OnItemsSourceChanged((IEnumerable)e.OldValue, (IEnumerable)e.NewValue);
}
private void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
{
MisItems = newValue;
// Remove handler for oldValue.CollectionChanged
var oldValueINotifyCollectionChanged = oldValue as INotifyCollectionChanged;
if (null != oldValueINotifyCollectionChanged)
{
oldValueINotifyCollectionChanged.CollectionChanged -= new NotifyCollectionChangedEventHandler(newValueINotifyCollectionChanged_CollectionChanged);
}
// Add handler for newValue.CollectionChanged (if possible)
var newValueINotifyCollectionChanged = newValue as INotifyCollectionChanged;
if (null != newValueINotifyCollectionChanged)
{
newValueINotifyCollectionChanged.CollectionChanged += new NotifyCollectionChangedEventHandler(newValueINotifyCollectionChanged_CollectionChanged);
}
}
void newValueINotifyCollectionChanged_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
//Do your stuff here.
}
The ItemsSource property is represented by a IEnumerable Object. Now I need to convert it to a Dictionary<object,string> in this function:
protected SearchResult DoSearch(string searchTerm)
{
if (!string.IsNullOrEmpty(searchTerm))
{
SearchResult sr = new SearchResult();
//var ItemsText = MisItems.GetType();
var p = (List<string>)MisItems;
/*sr.Results = ItemsText.Select((x, i) => new { x, i }).Where(x=>x.ToString().ToUpper().Contains(searchTerm.ToUpper()))
.ToDictionary(a => (object)a.i, a => a.x);*/
return sr;
}
else return new SearchResult();
}
How can i make the transition?
EDIT
More info:
My viewmodel has this property:
public List<EnumeradorWCFModel> Clientes { get; set; }
The data for this property is returned by a WCF service:
Clientes = _svc.Clientes_Enum(sTicket, "");
Then I wanted my UserControl to bind to this property. I create my control like this:
<autocomplete:TextBoxAutoComplete x:Name="Clientes" ItemsSource = "{Binding Path=Clientes}" DisplayMemberPath="Descripcion" Height="25"/>
[s]Alright. You posted a lot of code (that I personally think is unnecessary for what you're trying to do).
Let's slim it down.
You have an IEnumerable<string> to start out, correct? Good.
There's a ToDictionary() extension method in the LINQ libraries. Documentation is here.
So what you need to do is the following:
IEnumerable<string> myEnumerableOfStrings = new List<string>();
Dictionary<object, string> dictionary = myEnumerableOfStrings.ToDictionary(value => (object) value);
And here's a Fiddle as an example.
Alright, so we have just an IEnumerable with no strong type. (First I've ever seen or heard of this being done, but the same principles should apply.)
We need to create a local dictionary and iterate over that collection.
var myDictionary = new Dictionary<object, string>();
IEnumerable myCollection = new List<string>();
foreach(var item in myCollection)
{
// This might be fun if you get two of the same object in the collection.
// Since this key is based off of the results of the GetHashCode() object in the base object class.
myDictionary.Add((object) item, item.ToString());
}
Here's an example of that.
The above answer's example for ToDictionary extension, is a List of a primitive type (string), I would like to demonstrate converting a List of a complex type (class) into dictionary.
This overload is constructing a dictionary out of keySelector function and elementSelector function (docs):
public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector);
For example:
public class FooClass
{
public int FooKey { get; set; }
public string FooValue { get; set; }
}
IENumerable<FooClass> foos = new List<FooClass>();
IDictionary<int, string> dict = foos.ToDictionary<int, string>(x=>x.FooKey, x=>x.FooValue);

LINQ: Use .Except() on collections of different types by making them convertible/comparable?

Given two lists of different types, is it possible to make those types convertible between or comparable to each other (eg with a TypeConverter or similar) so that a LINQ query can compare them? I've seen other similar questions on SO but nothing that points to making the types convertible between each other to solve the problem.
Collection Types:
public class Data
{
public int ID { get; set; }
}
public class ViewModel
{
private Data _data;
public ViewModel(Data data)
{
_data = data;
}
}
Desired usage:
public void DoMerge(ObservableCollection<ViewModel> destination, IEnumerable<Data> data)
{
// 1. Find items in data that don't already exist in destination
var newData = destination.Except(data);
// ...
}
It would seem logical that since I know how to compare an instance of ViewModel to an instance of Data I should be able to provide some comparison logic that LINQ would then use for queries like .Except(). Is this possible?
I assume that providing a projection from Data to ViewModel is problematic, so I'm offering another solution in addition to Jason's.
Except uses a hash set (if I recall correctly), so you can get similar performance by creating your own hashset. I'm also assuming that you are identifying Data objects as equal when their IDs are equal.
var oldIDs = new HashSet<int>(data.Select(d => d.ID));
var newData = destination.Where(vm => !oldIDs.Contains(vm.Data.ID));
You might have another use for a collection of "oldData" elsewhere in the method, in which case, you would want to do this instead. Either implement IEquatable<Data> on your data class, or create a custom IEqualityComparer<Data> for the hash set:
var oldData = new HashSet<Data>(data);
//or: var oldData = new HashSet<Data>(data, new DataEqualityComparer());
var newData = destination.Where(vm => !oldData.Contains(vm.Data));
I know this is late but there is a simpler syntax using Func that eliminates the need for a comparer.
public static class LinqExtensions
{
public static IEnumerable<TSource> Except<TSource, VSource>(this IEnumerable<TSource> first, IEnumerable<VSource> second, Func<TSource, VSource, bool> comparer)
{
return first.Where(x => second.Count(y => comparer(x, y)) == 0);
}
public static IEnumerable<TSource> Contains<TSource, VSource>(this IEnumerable<TSource> first, IEnumerable<VSource> second, Func<TSource, VSource, bool> comparer)
{
return first.Where(x => second.FirstOrDefault(y => comparer(x, y)) != null);
}
public static IEnumerable<TSource> Intersect<TSource, VSource>(this IEnumerable<TSource> first, IEnumerable<VSource> second, Func<TSource, VSource, bool> comparer)
{
return first.Where(x => second.Count(y => comparer(x, y)) == 1);
}
}
so with lists of class Foo and Bar
public class Bar
{
public int Id { get; set; }
public string OtherBar { get; set; }
}
public class Foo
{
public int Id { get; set; }
public string OtherFoo { get; set; }
}
one can run Linq statements like
var fooExceptBar = fooList.Except(barList, (f, b) => f.Id == b.Id);
var barExceptFoo = barList.Except(fooList, (b, f) => b.OtherBar == f.OtherFoo);
it's basically a slight variation on above but seems cleaner to me.
If you use this :
var newData = destination.Except(data.Select(x => f(x)));
You have to project 'data' to same type contained in 'destination', but using the code below you could get rid of this limitation :
//Here is how you can compare two different sets.
class A { public string Bar { get; set; } }
class B { public string Foo { get; set; } }
IEnumerable<A> setOfA = new A[] { /*...*/ };
IEnumerable<B> setOfB = new B[] { /*...*/ };
var subSetOfA1 = setOfA.Except(setOfB, a => a.Bar, b => b.Foo);
//alternatively you can do it with a custom EqualityComparer, if your not case sensitive for instance.
var subSetOfA2 = setOfA.Except(setOfB, a => a.Bar, b => b.Foo, StringComparer.OrdinalIgnoreCase);
//Here is the extension class definition allowing you to use the code above
public static class IEnumerableExtension
{
public static IEnumerable<TFirst> Except<TFirst, TSecond, TCompared>(
this IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
Func<TFirst, TCompared> firstSelect,
Func<TSecond, TCompared> secondSelect)
{
return Except(first, second, firstSelect, secondSelect, EqualityComparer<TCompared>.Default);
}
public static IEnumerable<TFirst> Except<TFirst, TSecond, TCompared>(
this IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
Func<TFirst, TCompared> firstSelect,
Func<TSecond, TCompared> secondSelect,
IEqualityComparer<TCompared> comparer)
{
if (first == null)
throw new ArgumentNullException("first");
if (second == null)
throw new ArgumentNullException("second");
return ExceptIterator<TFirst, TSecond, TCompared>(first, second, firstSelect, secondSelect, comparer);
}
private static IEnumerable<TFirst> ExceptIterator<TFirst, TSecond, TCompared>(
IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
Func<TFirst, TCompared> firstSelect,
Func<TSecond, TCompared> secondSelect,
IEqualityComparer<TCompared> comparer)
{
HashSet<TCompared> set = new HashSet<TCompared>(second.Select(secondSelect), comparer);
foreach (TFirst tSource1 in first)
if (set.Add(firstSelect(tSource1)))
yield return tSource1;
}
}
Some may argue that's memory inefficient due to the use of an HashSet. But actually the Enumerable.Except method of the framework is doing the same with a similar internal class called 'Set' (I took a look by decompiling).
Your best bet is to provide a projection from Data to ViewModel so that you can say
var newData = destination.Except(data.Select(x => f(x)));
where f maps Data to ViewModel. You will need a IEqualityComparer<Data> too.

How to get the index of an element in an IEnumerable?

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

How can I sort List<T> based on properties of T?

My Code looks like this :
Collection<NameValueCollection> optionInfoCollection = ....
List<NameValueCollection> optionInfoList = new List<NameValueCollection>();
optionInfoList = optionInfoCollection.ToList();
if(_isAlphabeticalSoting)
Sort optionInfoList
I tried optionInfoList.Sort() but it is not working.
Using the sort method and lambda expressions, it is really easy.
myList.Sort((a, b) => String.Compare(a.Name, b.Name))
The above example shows how to sort by the Name property of your object type, assuming Name is of type string.
If you just want Sort() to work, then you'll need to implement IComparable or IComparable<T> in the class.
If you don't mind creating a new list, you can use the OrderBy/ToList LINQ extension methods. If you want to sort the existing list with simpler syntax, you can add a few extension methods, enabling:
list.Sort(item => item.Name);
For example:
public static void Sort<TSource, TValue>(
this List<TSource> source,
Func<TSource, TValue> selector)
{
var comparer = Comparer<TValue>.Default;
source.Sort((x, y) => comparer.Compare(selector(x), selector(y)));
}
public static void SortDescending<TSource, TValue>(
this List<TSource> source,
Func<TSource, TValue> selector)
{
var comparer = Comparer<TValue>.Default;
source.Sort((x, y) => comparer.Compare(selector(y), selector(x)));
}
public class Person {
public string FirstName { get; set; }
public string LastName { get; set; }
}
List<Person> people = new List<Person>();
people.Sort(
delegate(Person x, Person y) {
if (x == null) {
if (y == null) { return 0; }
return -1;
}
if (y == null) { return 0; }
return x.FirstName.CompareTo(y.FirstName);
}
);
You need to set up a comparer that tells Sort() how to arrange the items.
Check out List.Sort Method (IComparer) for an example of how to do this...

Categories