c# generic list merge - c#

Way I could not merge List and List? OOP says MyType2 is MyType...
using System;
using System.Collections.Generic;
namespace two_list_merge
{
public class MyType
{
private int _attr1 = 0;
public MyType(int i)
{
Attr1 = i;
}
public int Attr1
{
get { return _attr1; }
set { _attr1 = value; }
}
}
public class MyType2 : MyType
{
private int _attr2 = 0;
public MyType2(int i, int j)
: base(i)
{
Attr2 = j;
}
public int Attr2
{
get { return _attr2; }
set { _attr2 = value; }
}
}
class MainClass
{
public static void Main(string[] args)
{
int count = 5;
List<MyType> list1 = new List<MyType>();
for(int i = 0; i < count; i++)
{
list1[i] = new MyType(i);
}
List<MyType2> list2 = new List<MyType2>();
for(int i = 0; i < count; i++)
{
list1[i] = new MyType2(i, i*2);
}
list1.AddRange((List<MyType>)list2);
}
}
}

I'm going to assume that you're not using C# 4.0.
In earlier versions of C#, this won't work because the language doesn't support contravariance and covariance of generic types.
Don't worry about the academic jargon - they're just the terms for the kinds of variance (i.e. variation) permitted.
Here's a good article on the details:
http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx
To make your code work, write this:
list1.AddRange(list2.Cast<MyType>());

If you're using C#4 (.NET 4), you can simply remove the cast in your last line:
list1.AddRange(list2);
If you're using C#3 (.NET 3.5), you need to using the Cast() LINQ extension:
list1.AddRange(list2.Cast<MyType>());
The reason that you can't cast list2 to List is that List is not covariant. You can find a good explanation of why this is not the case here:
In C#, why can't a List<string> object be stored in a List<object> variable
The reason the first line works is that AddRange() takes an IEnumerable and IEnumerable is covariant. .NET 3.5 does not implement covariance of generic collections and hence the need for the Cast() in C#3.

Perhaps try using LINQ if you can, along with an explicit cast to MyType. Using C# 4.
List<MyType> list1 = new List<MyType>
{ new MyType(1), new MyType(2), new MyType(3)};
List<MyType2> list2 = new List<MyType2>
{ new MyType2(11,123), new MyType2(22,456), new MyType2(33, 789) };
var combined = list1.Concat(list2.AsEnumerable<MyType>());

Related

Least ugly way to "methodize" the creation of Lists containing Objects from various classes

I am a turbo newbie when it comes to programming, but I need to learn the ropes for a job.
I made a MyLists class reserved for creating and storing various Lists made out of various classes of objects, but I feel I'm going against the DRY principle, here's a snippet:
public class MyLists
{
private List<Apple> ListedApples = new List<Apple>();
private List<Orange> ListedOranges = new List<Orange>();
}
I made methods to enlist each:
public class MyLists
{
public List<Apple> AppleLister(int howMany)
{
List<Apple> appleList = new List<Apple>();
for (int i = 0; i < howMany; i++)
{
Apple apple = new Apple();
appleList.Add(apple);
}
ListedApples = appleList;
return ListedApples;
}
public List<Orange> OrangeLister(int howMany)
{
List<Orange> orangeList = new List<Orange>();
for (int i = 0; i < howMany; i++)
{
Orange orange = new Orange();
orangeList.Add(orange);
}
ListedOranges = orangeList;
return ListedOranges;
}
}
I felt it was too redundant and ugly, so I tried making a generics approach that could be invokable for whatever class is needed:
public static void Lister<T>(List<T> list, int howMany) where T : class
{
new List<T>();
for (int i = 0; i < howMany; i++)
{
var instance = Activator.CreateInstance(typeof(T), new object());
list.Add(instance);
}
return List<T>();
}
Naturally it didn't work, seems that mixing generic lists with objects is harder than mixing oil and water, I know there's a C# equivalent of a surfactant (change type maybe?), but after investigating around, the consensus is that such mixing should be generally avoided.
So my question now is, in what other way could one "methodize" a general enlister in this kind of scenario? The plan is to add objects which will be containing bits of info, namely location.
Thanks and best regards.
I can't say I'm a fan of what you're doing but, in order to make it work, you should add a new constraint to your generic type parameter. That way, you will be able to invoke the parameterless constructor of type T:
public static void Lister<T>(List<T> list, int howMany) where T : class, new()
{
for (int i = 0; i < howMany; i++)
{
list.Add(new T());
}
}
I've also removed the superfluous parts of that code.
You might also streamline the implementation somewhat with some LINQ:
list.AddRange(Enumerable.Range(1, howMany).Select(n => new T()));
Note that, if you want to be able to create a new list inside that method if one doesn't already exist, you should declare the first parameter ref:
public static void Lister<T>(ref List<T> list, int howMany) where T : class, new()
{
if (list == null)
{
list = new List<T>();
}
for (int i = 0; i < howMany; i++)
{
list.Add(new T());
}
}
Actually, it looks like your original type-specific methods don't take a list as input and always return a new one, so that would translate to a generic method like this:
public static List<T> Lister<T>(int howMany) where T : class, new()
{
var list = new List<T>();
for (int i = 0; i < howMany; i++)
{
list.Add(new T());
}
return list;
}

Returning a reference of a struct instead of a copy on C# 3.0?

I have this code:
using System;
using System.Collections.Generic;
using UnityEngine;
public interface HaveId
{
int id { get; }
}
public struct BusinessData : HaveId
{
// business type data
public int graphic_asset_id;
public string name;
public int id { get; set; }
}
public class LookupHelper<T> where T: HaveId
{
private T[] _list;
public T[] list
{
get { return _list; }
set { _list = value; _mapToDictionary(); }
}
private Dictionary<int, int> idxById = new Dictionary<int, int>();
public LookupHelper(){}
private void _mapToDictionary()
{
if(idxById.Count > 0) idxById = new Dictionary<int, int>();
for(var z =0 ; z < list.Length; ++z)
{
idxById[list[z].id] = z;
}
}
public bool IsIdExists(int id)
{
return idxById.ContainsKey(id);
}
public T ById(int id) // is this a reference?
{
var idx = idxById[id];
if (idx >= list.Length) throw new Exception(
String.Format("Invalid Index: {0} >= {1} on {2}",idx.ToString(),list.Length.ToString(), typeof(T).Name)
);
return list[idx];
}
}
And the test code:
LookupHelper<BusinessData> bd = new LookupHelper<BusinessData>();
bd.list = new BusinessData[]
{
new BusinessData{id = 1, name = "test"},
new BusinessData{id = 2, name = "test2"},
};
bd.ById(1).name = "foo";
This give an error: "Cannot modify struct member when accessed struct is not classified as a variable"
How can I change the value of first BusinessData and keep the array still allocated on a contiguous memory (array of struct, needed for cache locality)?
This should be a simple matter of splitting it up into a few lines. Extract the object to get a copy, modify the copy, then overwrite it in the array:
BusinessData bsd = bd.ById(1);
bsd.name = "foo";
bd.SetById(1, bsd);
Of course, you'll need to write that SetById method to reinsert things into the array:
public void SetById(int id, T obj)
{
Int32 idx = idxById[id];
list[idx] = obj;
}
As you know C# borrowed something’s from C and Java. But not everything.
In C, you can create a place for struct on the stack or the heap. On the heap, I can then pass a pointer around and change the content. Very powerful.
But C# emphasizes ease of memory management via garbage collection. To make it easy, C# has the concept of boxing value types into System.Object. Additional details, can be found on Microsoft C# Programming Guide on Boxing and unboxing.
So when you access the value type in your list, you have to explicitly unbox the value. Therefore it’s a copy of the item in the list. You can do what #Nyerguds suggested.
But to make life easy, why not turn your BusinessData into a class?

Iterating through two lists of two inherited classes (of the same base class)

I have two lists. The types of both lists inherit from the same base type. I want to iterate through them and do operations which only use functionality of the base class without having two basically identical foreach loops one after the other.
I can't copy the lists to another list or something of the sort, as I need to use the lists in their original form separately after the operation is complete.
Is there a way to do this without writing a function?
class Program
{
static void Main(string[] args)
{
// I have two lists of inherited classes
List<Babby1> list1 = returnBabby1();
List<Babby2> list2 = returnBabby2();
// I want to iterate through both, and do the same thing, which is a part
// of the base class functionality.
// Basically I want this to be a single foreach loop.
foreach (Babby1 item in list1)
item.var = 50;
foreach (Babby2 item in list2)
item.var = 50;
// I have to send them as separate lists, the type being the original (inherited) class
sendBabby1(list1);
sendBabby2(list2);
}
static void sendBabby1(List<Babby1> list)
{
}
static void sendBabby2(List<Babby2> list)
{
}
static List<Babby1> returnBabby1()
{
return new List<Babby1>();
}
static List<Babby2> returnBabby2()
{
return new List<Babby2>();
}
}
class Base
{
public int var;
}
class Babby1 : Base
{
public int var1;
}
class Babby2 : Base
{
public int var2;
}
This should do the trick...
foreach (var item in list1.Concat<Base>(list2))
{
// Do your thing
}
EDIT: I changed Union to Concat as I think that it's probably more appropriate.
Just use the base class, like this:
List<Babby> list = new List<Base>();
list.AddRange(returnBabby1());
list.AddRange(returnBabby2());
foreach (Base item in list)
item.var = 50;
sendBabby1(list.OfType<Babby1>().ToList());
sendBabby2(list.OfType<Babby2>().ToList());
(This of course assume you have the variable you set declared in the base class)
You can use the covariance of IEnumerable<T> in order to achieve this, if you plan to simply iterate the lists and not add items or perform other operations on the list:
static SendBaby(IEnumerable<Base> list)
{
...
}
...
SendBaby(list1)
SendBaby(list2)
You can use a for loop, using Count instead. (If comparisons do consume additional CPU cycles.)
for(int i=0;i<baby1.Count||i<baby2.Count;i++)
{
if(baby1.Count<i)
baby1[i].field = 50;
if(baby2.Count<i)
baby2[i].field = 50;
}
This does it pretty well :
var babies1 = new List<Baby1>(5);
for (int i = 0; i < 5; i++)
{
babies1.Add(new Baby1 { Name = "Babies1 " + i, Var1 = 1});
}
var babies2 = new List<Baby2>(5);
for (int i = 0; i < 5; i++)
{
babies2.Add(new Baby2 { Name = "Babies2 " + i });
}
foreach (Baby b in babies1.Union<Baby>(babies2))
{
b.Var1 = 50;
}
foreach (var baby2 in babies2)
{
Console.WriteLine(baby2.Var1);
}
foreach (var baby1 in babies1)
{
Console.WriteLine(baby1.Var1);
}

More efficent ways of cleanly dealing with a multi-dimensional array keyd by enums

I have a situation where I need to do many gets/sets, after perfomance analysis this is one of the more expensive parts of my application. Origionally I was using a Dictionary but switched to a jagged array internally which gave it a signficant perfomance boost, still I'd like to see if theres a way to improve the perfomance of this code without ditching the nice and useable syntax.
Note calling Convert.ToInt32 is signficantly more expensive than calling a cast, and since the generic constraint TStatus : int doesn't work for an enum I had to implement this as a abstract class, it would be nice if this collection would work with any enum out of the box.
Also I tried implementing yield for the IEnumerable, however that was actually slower than just populating a list.
public abstract class LoanStatusVectorOverTime<TStatus> : ILoanStatusVectorOverTime<TStatus>
where TStatus: struct
{
protected static readonly TStatus[] LoanStatusTypes = (TStatus[])Enum.GetValues(typeof(TStatus));
protected static readonly int LoanStatusCount = Enum.GetValues(typeof(TStatus)).Length;
protected const int MonthsSinceEventCount = 25;
private readonly object SYNC = new object();
protected double[,] VectorDictionary { get; set; }
public LoanStatusVectorOverTime()
{
this.VectorDictionary = new double[LoanStatusCount, MonthsSinceEventCount];
}
public double this[TStatus status, int monthsSince]
{
get
{
if (monthsSince >= MonthsSinceEventCount)
return 0;
return VectorDictionary[GetKeyValue(status), monthsSince];
}
set
{
if (monthsSince >= MonthsSinceEventCount)
return;
VectorDictionary[GetKeyValue(status), monthsSince] = value;
}
}
public double SumOverStatus(TStatus status)
{
double sum = 0;
foreach (var fromStatus in LoanStatusTypes)
{
int i = 0;
while (i < MonthsSinceEventCount)
{
sum += VectorDictionary[GetKeyValue(fromStatus), i];
i++;
}
}
return sum;
}
public IEnumerator<KeyValuePair<Tuple<TStatus, int>, double>> GetEnumerator()
{
List<KeyValuePair<Tuple<TStatus, int>, double>> data = new List<KeyValuePair<Tuple<TStatus, int>, double>>();
foreach (var fromStatus in LoanStatusTypes)
{
int i = 0;
while (i < MonthsSinceEventCount)
{
var val = VectorDictionary[GetKeyValue(fromStatus), i];
if (val != default(double))
data.Add(new KeyValuePair<Tuple<TStatus, int>, double>(new Tuple<TStatus, int>(fromStatus, i), val));
i++;
}
}
return data.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
protected abstract int GetKeyValue(TStatus status);
protected abstract ILoanStatusVectorOverTime<TStatus> Initalize();
public ILoanStatusVectorOverTime<TStatus> Copy()
{
var vect = Initalize();
foreach (var fromStatus in LoanStatusTypes)
{
int i = 0;
while (i < MonthsSinceEventCount)
{
vect[fromStatus, i] = VectorDictionary[GetKeyValue(fromStatus), i];
i++;
}
}
return vect;
}
public double SumOverAll(int monthsSince = 1)
{
double sum = 0;
foreach (var status in LoanStatusTypes)
{
sum += this[status, monthsSince];
}
return sum;
}
}
public class AssetResolutionVector : LoanStatusVectorOverTime<AssetResolutionStatus>
{
protected override int GetKeyValue(AssetResolutionStatus status)
{
return (int)status;
}
protected override ILoanStatusVectorOverTime<AssetResolutionStatus> Initalize()
{
return new AssetResolutionVector();
}
}
var arvector = new AssetResolutionVector();
arvector[AssetResolutionStatus.ShortSale, 1] = 10;
If the enum to int conversion is taking up a lot of your time, make sure that don't do the conversion during every iteration of your inner loop. Here's an example of the conversion getting cached for your SumOverStatus method:
public double SumOverStatus(TStatus status)
{
double sum = 0;
foreach (var fromStatus in LoanStatusTypes)
{
int statusKey = GetKeyValue(fromStatus);
int i = 0;
while (i < MonthsSinceEventCount)
{
sum += VectorDictionary[statusKey, i];
i++;
}
}
return sum;
}
Extra tip: although it may not have give a performance boost, you can avoid making your class abstract by using a Func<TStatus, int> converter. Here's how the converter could be exposed as a property (a constructor argument would work fine too):
public class LoanStatusVectorOverTime<TStatus>
{
public Func<TStatus, int> GetKeyValue { get; set; }
}
// When the object gets instantiated
loanStatusVectorOverTime.GetKeyValue = status => (int)status;
It sounds like you have two separate problems here:
Converting from an enum to an integer has an overhead when the conversion is being done using an abstract method or a delegate. You have two options here:
A. Take out the generic parameter from your class and hardcode the enum type (making multiple copies of the class if necessary).
B. Have your accessors take two integers instead of an enum and an integer (letting the client do a cheap cast from enum to integer).
A lot of time is being used during get/set. This may not be because get/set are inefficient, but because get/set are being called too many times. Suggestions:
A. Group your operations by month or by status, restructure your data structures (maybe using nested arrays), and write efficient loops.
B. Reduce the computational complexity of the code that is doing all the getting and setting. By stepping back and mapping out your program, you may find more efficient algorithms.

Deep copy of List<T>

I'm trying to make a deep copy of a generic list, and am wondering if there is any other way then creating the copying method and actually copying over each member one at a time. I have a class that looks somewhat like this:
public class Data
{
private string comment;
public string Comment
{
get { return comment; }
set { comment = value; }
}
private List<double> traceData;
public List<double> TraceData
{
get { return traceData; }
set { traceData = value; }
}
}
And I have a list of the above data, i.e List<Data>. What I'm trying to do is plot a trace data of the subset of List onto a graph, possibly with some scaling or sweeping on the data. I obviously don't need to plot everything in the list because they don't fit into the screen.
I initially tried getting the subset of the list using the List.GetRange() method, but it seems that the underneath List<double> is being shallow copied instead of deep copied. When I get the subset again using List.GetRange(), I get previously modified data, not the raw data retrieved elsewhere.
Can anyone give me a direction on how to approach this? Thanks a lot.
The idiomatic way to approach this in C# is to implement ICloneable on your Data, and write a Clone method that does the deep copy (and then presumably a Enumerable.CloneRange method that can clone part of your list at once.) There isn't any built-in trick or framework method to make it easier than that.
Unless memory and performance are a real concern, I suggest that you try hard to redesign it to operate on immutable Data objects, though, instead. It'll wind up much simpler.
You can try this
public static object DeepCopy(object obj)
{
if (obj == null)
return null;
Type type = obj.GetType();
if (type.IsValueType || type == typeof(string))
{
return obj;
}
else if (type.IsArray)
{
Type elementType = Type.GetType(
type.FullName.Replace("[]", string.Empty));
var array = obj as Array;
Array copied = Array.CreateInstance(elementType, array.Length);
for (int i = 0; i < array.Length; i++)
{
copied.SetValue(DeepCopy(array.GetValue(i)), i);
}
return Convert.ChangeType(copied, obj.GetType());
}
else if (type.IsClass)
{
object toret = Activator.CreateInstance(obj.GetType());
FieldInfo[] fields = type.GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance);
foreach (FieldInfo field in fields)
{
object fieldValue = field.GetValue(obj);
if (fieldValue == null)
continue;
field.SetValue(toret, DeepCopy(fieldValue));
}
return toret;
}
else
throw new ArgumentException("Unknown type");
}
Thanks to DetoX83 article on code project.
If IClonable way is too tricky for you. I suggest converting to something and back. It can be done with BinaryFormatter or a Json Converter like Servicestack.Text since it is the fastest one in .Net.
Code should be something like this:
MyClass mc = new MyClass();
string json = mc.ToJson();
MyClass mcCloned = json.FromJson<MyClass>();
mcCloned will not reference mc.
The most easiest (but dirty) way is to implement ICloneable by your class and use next extension method:
public static IEnumerable<T> Clone<T>(this IEnumerable<T> collection) where T : ICloneable
{
return collection.Select(item => (T)item.Clone());
}
Usage:
var list = new List<Data> { new Data { Comment = "comment", TraceData = new List { 1, 2, 3 } };
var newList = list.Clone();
another thing you can do is mark your class as serializable and use binary serialization.
Here is a working example
public class Program
{
[Serializable]
public class Test
{
public int Id { get; set; }
public Test()
{
}
}
public static void Main()
{
//create a list of 10 Test objects with Id's 0-10
List<Test> firstList = Enumerable.Range(0,10).Select( x => new Test { Id = x } ).ToList();
using (var stream = new System.IO.MemoryStream())
{
var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
binaryFormatter.Serialize(stream, firstList); //serialize to stream
stream.Position = 0;
//deserialize from stream.
List<Test> secondList = binaryFormatter.Deserialize(stream) as List<Test>;
}
Console.ReadKey();
}
}
If you make your objects immutable you don't need to worry about passing around copies of them, then you could do something like:
var toPlot = list.Where(d => d.ShouldBePlotted());
Since your collection is mutable, you need to implement the deep copy programmatically:
public class Data
{
public string Comment { get; set; }
public List<double> TraceData { get; set; }
public Data DeepCopy()
{
return new Data
{
Comment = this.Comment,
TraceData = this.TraceData != null
? new List<double>(this.TraceData)
: null;
}
}
}
The Comment field can be shallow copied because its already an immutable class. You need to create a new list for TraceData, but the elements themselves are immutable and require no special handling to copy them.
When I get the subset again using
List.GetRange(), I get previously
modified data, not the raw data
retrieved elsewhere.
Use your new DeepCopy method as such:
var pointsInRange = dataPoints
.Select(x => x.DeepCopy())
.GetRange(start, length);
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DeepListCopy_testingSome
{
class Program
{
static void Main(string[] args)
{
List<int> list1 = new List<int>();
List<int> list2 = new List<int>();
//populate list1
for (int i = 0; i < 20; i++)
{
list1.Add(1);
}
///////
Console.WriteLine("\n int in each list1 element is:\n");
///////
foreach (int i in list1)
{
Console.WriteLine(" list1 elements: {0}", i);
list2.Add(1);
}
///////
Console.WriteLine("\n int in each list2 element is:\n");
///////
foreach (int i in list2)
{
Console.WriteLine(" list2 elements: {0}", i);
}
///////enter code here
for (int i = 0; i < list2.Count; i++)
{
list2[i] = 2;
}
///////
Console.WriteLine("\n Printing list1 and list2 respectively to show\n"
+ " there is two independent lists,i e, two differens"
+ "\n memory locations after modifying list2\n\n");
foreach (int i in list1)
{
Console.WriteLine(" Printing list1 elements: {0}", i);
}
///////
Console.WriteLine("\n\n");
///////
foreach (int i in list2)
{
Console.WriteLine(" Printing list2 elements: {0}", i);
}
Console.ReadKey();
}//end of Static void Main
}//end of class
}
One quick and generic way to deeply serialize an object is to use JSON.net. The following extension method allows serializing of a list of any arbitrary objects, but is able to skip Entity Framework navigation properties, since these may lead to circular dependencies and unwanted data fetches.
Method
public static List<T> DeepClone<T>(this IList<T> list, bool ignoreVirtualProps = false)
{
JsonSerializerSettings settings = new JsonSerializerSettings();
if (ignoreVirtualProps)
{
settings.ContractResolver = new IgnoreNavigationPropsResolver();
settings.PreserveReferencesHandling = PreserveReferencesHandling.None;
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
settings.Formatting = Formatting.Indented;
}
var serialized = JsonConvert.SerializeObject(list, settings);
return JsonConvert.DeserializeObject<List<T>>(serialized);
}
Usage
var clonedList = list.DeepClone();
By default, JSON.NET serializes only public properties. If private properties must be also cloned, this solution can be used.
This method allows for quick (de)serialization of complex hierarchies of objects.

Categories

Resources