I have a quite odd question. I am working on a big project and i am implementing a core feature after millions of lines of code. I am not allowed to alter some parts of the code and it seems like i have to try this way.
I have two classes as A and B. A is derived from B.
public class B{}
public class A : B{}
I have a SortedList<string, A>, i need to cast the SortedList into List<B>. Operate on List<B> then cast the list into SortedList again.
For example:
SortedList<string, B> items;
public List<A> GetItems()
{
return items.Values.Cast<B>().ToList(); //Getting values works
}
public void SetItems(List<B> newItems)
{
items = CastWithMagic(newItems); //How to make casting work?
}
There are 2 possible changes on A items.
Changes on B(base class variables)
Removed items from the list.
I want to apply changes on List<B> to SortedList<string, A>
There are 2 possible changes on A items.
Changes on B(base class variables)
Removed items from the list.
Changes to the objects will be reflected in both lists, since the lists just contain references to the same objects. So all you should need to handle is objects that are deleted from the List. I believe you'll have to loop through the sorted list to see if the objects have been removed from the list:
public void SetItems(List<B> newItems)
{
foreach(string key in items.Keys)
{
if(!newItems.Contains(items[key] as B))
items.Remove(key);
}
}
Note that this is inefficient since you're looping through both collections, making it O(m*n) - if your collections are small and performance is not critical then you may be OK, but start with this and find ways to make it more efficient (maybe removing from the source collection instead of the copied list?)
You might be able to use Linq's 'select' function for this. Take this example code:
private void test()
{
List<alphaClass> firstList = new List<alphaClass>();
List<betaClass> secondList = firstList.Select(z => (betaClass)z).ToList();
}
public class alphaClass { }
public class betaClass : alphaClass { }
(This assumes everything from the list can be cast as the derived class.)
Anyway, linq's SELECT statement can be used to transform an IEnumerable into a different form. In this case, transforming it from one class to another.
EDIT: Whoops - missed the Sorted List part. That can be taken care of by using an extension method I found for a different question:
public static class ExtensionMethod
{
public static SortedList<TKey, TValue> ToSortedList<TSource, TKey, TValue>
(this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TValue> valueSelector)
{
var ret = new SortedList<TKey, TValue>();
foreach (var element in source)
{
ret.Add(keySelector(element), valueSelector(element));
}
return ret;
}
}
... and then, from here, you can use that extension like this:
SortedList<string, betaClass> myList = new SortedList<string, betaClass>();
SortedList<string, alphaClass> secondList;
secondList = myList.ToSortedList(kvp => kvp.Key, kvp => (alphaClass) kvp.Value);
Related
I am trying to give out a IReadOnly-references to internal Collection objects.
This works well in most cases, but does not if i want to convert a dictionary containing a collection into an IReadOnlyDictionary containing a IReadOnlyCollection.
Here a code example:
var list = new List<int>();
IReadOnlyList<int> listReference = list; //works;
var dictionary = new Dictionary<int, int>();
IReadOnlyDictionary<int, int> dictionaryReference = dictionary; //works
var nestedList = new List<List<int>>();
IReadOnlyList<IReadOnlyList<int>> nestedReadOnlyListReference = nestedList; //works
var nestedDictionary = new Dictionary<int, List<int>>();
//IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary; //does not work, can not implicitly convert
//current workaround
var nestedDictionaryReferenceHelper = new Dictionary<int, IReadOnlyList<int>>();
foreach (var kvpNestedDictionary in nestedDictionary)
{
nestedDictionaryReferenceHelper.Add(kvpNestedDictionary.Key, (IReadOnlyList<int>)kvpNestedDictionary.Value);
}
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionaryReferenceHelper; //works, but is only a reference to the internal List, not to the dictionary itself
The workaround is pretty ugly as it needs additional memory and needs manual updating every time the values of nestedDictionary change.
Is there any simple way to convert such nested dictionaries?
In this SO question you can find a very good explanation why casting dictionary values is not supported. Please see the accepted answer of Eric Lippert.
Although i would not recommend this, you could use the following LINQ expression to cast the values of the dictionary to a read only list:
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary.ToDictionary(kv => kv.Key, kv => kv.Value as IReadOnlyList<int>);
It is a shorter version of your workaround and it is lazy evaluated, but i would not recommend this due to the following reasons:
This solution still creates a copy of the dictionary and does not update any new/deleted entries from the original dictionary.
The values of the dictionary, i.e. the readonly lists, refer to the original lists and changes there are updated in the read only versions in the dictionary too.
This is inconsistent behavior and therefore a bad practice!
Unless it is not possible to cast the values of a dictionary, i would not recommend doing this. You should either deep copy the entire dictionary including the nested lists, or use an other container that supports casting.
In my opinion the point is the you're missing the opportunity to introduce a proper new type with its own dignity. If you're using Dictionary<int, List<int>> then you will see yourself with code like this every time you need to insert a value:
if (!_dictionary.ContainsKey(key)) {
var list = new List<int>();
list.Add(value);
_dictionary.Add(key, list);
} else {
_dictionary[key].Add(value);
}
And even worse with code like this when you want to search for a value:
_dictionary.ContainsKey(key) && _dictionary[key].Contains(value);
And variation of those examples. What's worse you're exposing this implementation detail to your class users. If this detail will change then you will break all code. What, for example, if you want to replace List<int> with HashSet<int>?
How it should be?
_multimap.Add(key, value);
With a proper interface (here I show just few methods):
public interface IMultiMap<TKey, TValue> {
void Add(TKey key, TValue value);
bool ContainsKey(TKey key);
}
And its implementation:
public sealed class MultiMap<TKey, TValue> : IMultiMap<TKey, TValue> {
// ...
private Dictionary<int, List<int>> _items;
}
You can introduce IReadOnlyMultiMap<TKey, TValue>:
public interface IReadOnlyMultiMap<TKey, TValue> {
bool ContainsKey(TKey key);
}
Just implement IReadOnlyMultiMap<TKey, TValue> in MultiMap<TKey, TValue> and to return a read-only collection you have nothing to do (fictional example):
IReadOnlyMultiMap<int, int> MakeReadOnly(MultiMap<int, int> map) {
return map; // Nothing to do!
}
Note that you may want to introduce a new ReadOnlyMultiMap<TKey, TValue> to tunnel read calls to underlying live collection (to avoid callers to simply cast to MultiMap<TKey, TValue> to circumvent read-only limitation). Proof of concept:
public sealed class ReadOnlyMultiMap<TKey, TValue> : IReadOnlyMultiMap<TKey, TValue> {
public ReadOnlyMultiMap(IMultiMap<TKey, TValue> collection) {
_collection = collection;
}
public bool ContainsKey(TKey key) {
return _collection.ContainsKey(key);
}
private readonly IMultiMap<TKey, TValue> _collection;
}
To return a read-only view you do:
IReadOnlyMultiMap<int, int> MakeReadOnly(MultiMap<int, int> map) {
return new ReadOnlyMultiMap<int, int>(map);
}
Note that I talked about implementation detail. You're still exposing an implementation detail (you're using a multimap) then if such code is for a public API you should introduce a new (properly named) type to describe what it contains, not how storage is implemented. It may be MeasureCollection, SoccerScoreCollection or whatever your model is talking about, storage may vary but content won't.
Problem for conversion failing is the KeyValuePair:
Although class Derived inheriting class Base, KeyValuePair is not a sub class of KeyValuePair; see definitions(Dictionary, IReadOnlyDictionary).
So you always will need some kind of workaround (MultiMap approach appears to me as one, too...). If nestedDictionary is private, so you have complete control over it from your class, you might get away with this:
var nestedDictionary = new Dictionary<int, IReadOnlyList<int>>();
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary;
and whenever modifying a list within the dictionary applying a cast to List<int>. Another ugly workaround, I admit, but saves you extra memory and redundancy management and retains the (asumed...) public interface of IReadOnlyDictionary<int, IReadOnlyList<int>>.
Edit: just an idea, haven't tested, but it might work: Have your own dictionary adding the missing interfaces to be assignable to the read-only dictionary:
public class MyDictionary
: Dictionary<int, List<int>>,
ICollection<KeyValuePair<int, IReadOnlyList<int>>,
IEnumerable<KeyValuePair<int, IReadOnlyList<int>>,
IReadOnlyCollection<KeyValuePair<int, IReadOnlyList<int>>
{
}
I might yet have missed an interface to be implemented, and you might have to implement some members yet. If it works, possibly the cleanest solution...
I am trying to give out a IReadOnly-references to internal Collection objects.
This works well in most cases, but does not if i want to convert a dictionary containing a collection into an IReadOnlyDictionary containing a IReadOnlyCollection.
Here a code example:
var list = new List<int>();
IReadOnlyList<int> listReference = list; //works;
var dictionary = new Dictionary<int, int>();
IReadOnlyDictionary<int, int> dictionaryReference = dictionary; //works
var nestedList = new List<List<int>>();
IReadOnlyList<IReadOnlyList<int>> nestedReadOnlyListReference = nestedList; //works
var nestedDictionary = new Dictionary<int, List<int>>();
//IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary; //does not work, can not implicitly convert
//current workaround
var nestedDictionaryReferenceHelper = new Dictionary<int, IReadOnlyList<int>>();
foreach (var kvpNestedDictionary in nestedDictionary)
{
nestedDictionaryReferenceHelper.Add(kvpNestedDictionary.Key, (IReadOnlyList<int>)kvpNestedDictionary.Value);
}
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionaryReferenceHelper; //works, but is only a reference to the internal List, not to the dictionary itself
The workaround is pretty ugly as it needs additional memory and needs manual updating every time the values of nestedDictionary change.
Is there any simple way to convert such nested dictionaries?
In this SO question you can find a very good explanation why casting dictionary values is not supported. Please see the accepted answer of Eric Lippert.
Although i would not recommend this, you could use the following LINQ expression to cast the values of the dictionary to a read only list:
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary.ToDictionary(kv => kv.Key, kv => kv.Value as IReadOnlyList<int>);
It is a shorter version of your workaround and it is lazy evaluated, but i would not recommend this due to the following reasons:
This solution still creates a copy of the dictionary and does not update any new/deleted entries from the original dictionary.
The values of the dictionary, i.e. the readonly lists, refer to the original lists and changes there are updated in the read only versions in the dictionary too.
This is inconsistent behavior and therefore a bad practice!
Unless it is not possible to cast the values of a dictionary, i would not recommend doing this. You should either deep copy the entire dictionary including the nested lists, or use an other container that supports casting.
In my opinion the point is the you're missing the opportunity to introduce a proper new type with its own dignity. If you're using Dictionary<int, List<int>> then you will see yourself with code like this every time you need to insert a value:
if (!_dictionary.ContainsKey(key)) {
var list = new List<int>();
list.Add(value);
_dictionary.Add(key, list);
} else {
_dictionary[key].Add(value);
}
And even worse with code like this when you want to search for a value:
_dictionary.ContainsKey(key) && _dictionary[key].Contains(value);
And variation of those examples. What's worse you're exposing this implementation detail to your class users. If this detail will change then you will break all code. What, for example, if you want to replace List<int> with HashSet<int>?
How it should be?
_multimap.Add(key, value);
With a proper interface (here I show just few methods):
public interface IMultiMap<TKey, TValue> {
void Add(TKey key, TValue value);
bool ContainsKey(TKey key);
}
And its implementation:
public sealed class MultiMap<TKey, TValue> : IMultiMap<TKey, TValue> {
// ...
private Dictionary<int, List<int>> _items;
}
You can introduce IReadOnlyMultiMap<TKey, TValue>:
public interface IReadOnlyMultiMap<TKey, TValue> {
bool ContainsKey(TKey key);
}
Just implement IReadOnlyMultiMap<TKey, TValue> in MultiMap<TKey, TValue> and to return a read-only collection you have nothing to do (fictional example):
IReadOnlyMultiMap<int, int> MakeReadOnly(MultiMap<int, int> map) {
return map; // Nothing to do!
}
Note that you may want to introduce a new ReadOnlyMultiMap<TKey, TValue> to tunnel read calls to underlying live collection (to avoid callers to simply cast to MultiMap<TKey, TValue> to circumvent read-only limitation). Proof of concept:
public sealed class ReadOnlyMultiMap<TKey, TValue> : IReadOnlyMultiMap<TKey, TValue> {
public ReadOnlyMultiMap(IMultiMap<TKey, TValue> collection) {
_collection = collection;
}
public bool ContainsKey(TKey key) {
return _collection.ContainsKey(key);
}
private readonly IMultiMap<TKey, TValue> _collection;
}
To return a read-only view you do:
IReadOnlyMultiMap<int, int> MakeReadOnly(MultiMap<int, int> map) {
return new ReadOnlyMultiMap<int, int>(map);
}
Note that I talked about implementation detail. You're still exposing an implementation detail (you're using a multimap) then if such code is for a public API you should introduce a new (properly named) type to describe what it contains, not how storage is implemented. It may be MeasureCollection, SoccerScoreCollection or whatever your model is talking about, storage may vary but content won't.
Problem for conversion failing is the KeyValuePair:
Although class Derived inheriting class Base, KeyValuePair is not a sub class of KeyValuePair; see definitions(Dictionary, IReadOnlyDictionary).
So you always will need some kind of workaround (MultiMap approach appears to me as one, too...). If nestedDictionary is private, so you have complete control over it from your class, you might get away with this:
var nestedDictionary = new Dictionary<int, IReadOnlyList<int>>();
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary;
and whenever modifying a list within the dictionary applying a cast to List<int>. Another ugly workaround, I admit, but saves you extra memory and redundancy management and retains the (asumed...) public interface of IReadOnlyDictionary<int, IReadOnlyList<int>>.
Edit: just an idea, haven't tested, but it might work: Have your own dictionary adding the missing interfaces to be assignable to the read-only dictionary:
public class MyDictionary
: Dictionary<int, List<int>>,
ICollection<KeyValuePair<int, IReadOnlyList<int>>,
IEnumerable<KeyValuePair<int, IReadOnlyList<int>>,
IReadOnlyCollection<KeyValuePair<int, IReadOnlyList<int>>
{
}
I might yet have missed an interface to be implemented, and you might have to implement some members yet. If it works, possibly the cleanest solution...
I have class with 5 fields.
public class Test
{
public string name;
public string description;
public int int1;
public int int2;
public int int3;
}
In one of my function I have List<Test> list which has 10 items. Here I want SortedList<string,string> for two properties name & description.
I know, I can achieve this using for each but I want to know How can I do this using LINQ?
Use this:
var result = list.OrderBy(x => x.Name).ThenBy(x => x.Description);
Important:
Don't use multiple calls to OrderBy as they overwrite each other.
The sorted result will be in result. The original list remains unchanged.
The answer from #HugoRune is quite exhaustive, but because you said you want to use Linq, I'd suggest to add an extension method in your scope to help you with your goal:
static class SortedListExtensions
{
public static SortedList<K, V> ToSortedList<K, V, T>(
this IEnumerable<T> source,
Func<T, K> keySelector, Func<T, V> valueSelector)
{
return new SortedList<K,V>(
source.ToDictionary(
cur => keySelector(cur),
cur => valueSelector(cur)));
}
}
this way your SortedList creation is composable in Linq computations:
var sl = list.ToSortedList(f => f.name, f => f.description);
A C# SortedList is a type of dictionary, not actually a list.
If you indeed want a SortedList containing the names as keys and the descriptions as values, you can use this:
SortedList slist = new SortedList(list.ToDictionary(t=>t.name, t=>t.description))
Be aware that if a name occurs twice this will throw an exception, since dictionary keys have to be unique.
For most practical purposes however, the solution posted by Daniel Hilgarth is what I would use, unless you have a library function that specifically requires a SortedList as parameter.
I have various ObservableCollections of different object types. I'd like to write a single method that will take a collection of any of these object types and return a new collection where each element is a deep copy of elements in the given collection. Here is an example for a specifc class
private static ObservableCollection<PropertyValueRow> DeepCopy(ObservableCollection<PropertyValueRow> list)
{
ObservableCollection<PropertyValueRow> newList = new ObservableCollection<PropertyValueRow>();
foreach (PropertyValueRow rec in list)
{
newList.Add((PropertyValueRow)rec.Clone());
}
return newList;
}
How can I make this method generic for any class which implements ICloneable?
You could do something like this:
private static ObservableCollection<T> DeepCopy<T>(ObservableCollection<T> list)
where T : ICloneable
{
ObservableCollection<T> newList = new ObservableCollection<T>();
foreach (T rec in list)
{
newList.Add((T)rec.Clone());
}
return newList;
}
Note that you could make this more general by taking IEnumerable<T>, and LINQ makes it even easier:
private static ObservableCollection<T> DeepCopy<T>(IEnumerable<T> list)
where T : ICloneable
{
return new ObservableCollection<T>(list.Select(x => x.Clone()).Cast<T>());
}
private static ObservableCollection<T> DeepCopy<T>(ObservableCollection<T> list)
where T : ICloneable
{
ObservableCollection<T> newList = new ObservableCollection<T>();
foreach (T rec in list)
{
newList.Add((T)rec.Clone());
}
return newList;
}
I use a very similar function which works with all ICollections which can be constructed (e.g. many standard collections):
public static TContainer CloneDeep<TContainer, T>( TContainer r )
where T : ICloneable
where TContainer: ICollection<T>, new()
{
// could use linq here, but this is my original pedestrian code ;-)
TContainer l = new TContainer();
foreach(var t in r)
{
l.Add( (T)t.Clone() );
}
return l;
}
Unfortunately the compiler isn't able to deduce the types so that one must pass them explicitly. For more than a handful calls I write a specialization. Here is an example for Lists (which itself can be called with implicitly deduced T).
public static List<T> CloneListDeep<T>( List<T> r ) where T : ICloneable
{
return CloneDeep<List<T>, T>( r );
}
I use this function extensively in order to create copies of lists serving as datasources for datagridviews on dialogs which can be canceled. The modified list is simply discarded when the dialog is cancelled; when the dialog is OKed the edited list simply replaces the original. Prerequisite for this pattern is, of course, to have a semantically correct and well maintained T.clone().
I recently started to learn about LINQ and came across the OrderBy extension method. This initially excited me because the syntax seemed much nicer than the Sort method that we use all over the place for Generic Lists.
For example, when sorting a list of languages, we normally do something like:
neutralCultures.Sort((x, y) => x.EnglishName.CompareTo(y.EnglishName));
This works well, but I prefer the syntax of OrderBy, which only requires that you pass in the property that you wish to sort by, like so:
neutralCultures.OrderBy(ci => ci.EnglishName);
The problem is that OrderBy returns IOrderedEnumerable, but I need List<T>. So, I set out to extend the Sort method for List<T> using the same signature that is used for OrderBy.
public static void Sort<TSource, TKey>(this List<TSource list, Func<TSource, TKey> keySelector)
{
list = list.OrderBy(keySelector).ToList<TSource>();
}
This would be called like:
neutralCultures.Sort(ci => ci.EnglishName);
Maybe I'm overlooking a simple implementation detail, but this code doesn't work. It compiles, but doesn't return an ordered list. I'm sure I can refactor this to make it work, but I was just wondering why setting list within the extension method doesn't work.
I've written Sort variants using a selector before - it isn't hard... something like:
using System;
using System.Collections.Generic;
class Foo
{
public string Bar { get; set; }
}
static class Program
{
static void Main()
{
var data = new List<Foo> {
new Foo {Bar = "def"},
new Foo {Bar = "ghi"},
new Foo {Bar = "abc"},
new Foo {Bar = "jkl"}
};
data.Sort(x => x.Bar);
foreach (var item in data)
{
Console.WriteLine(item.Bar);
}
}
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)));
}
}
That's the behaviour I would expect. Imagine if such a thing were possible:
var c = myCustomer;
myCustomer.DoStuff();
if (c == myCustomer) // returns false!!!
Simply calling a method on an object (which is what an extension method looks like to the user of your framework) shouldn't change which instance the reference points to.
For your example, I would stick with Sort.
I think it is because list is not passed by ref. Thus setting the list variable to another object doesn't alter where the original variable was pointing.
You might be able to do this (haven't tested it properly):
public static void Sort<TSource, TKey>(this List<TSource> list, Func<TSource, TKey> keySelector)
{
var tempList = list.OrderBy(keySelector).ToList<TSource>();
list.Clear();
list.AddRange(tempList);
}
You are replacing the value of the local parameter variable called list, not changing the value of the caller's variable (which is what you are trying to do.)