C# Overload generic + operator - c#

I'm trying to make a list be able to added to by plusing an item into it.
Target use of code I'm trying to make happen:
List<int> numbers = new List<int>();
numbers += 10;
What I've tried.
"operator +" should overload + and "this IList" should extend generic IList.
public static IList<T> operator +<T>(this IList<T> list, T element)
{
list.Add(element);
return list;
}
It's not working however, red underlines everywhere over it in visual studios 2012.
What am I doing wrong? Is this not possible? Why could this work for a standard class but not a generic class?

Operators can only be overloaded in the definition of the class. You can't override them from outside by using extension methods.
Also, at least one of the parameters must be of the same type as the class.
So the best you can do is something like:
public class CustomList<T> : List<T>
{
public static CustomList<T> operator +(CustomList<T> list, T element)
{
list.Add(element);
return list;
}
}
That you can then use like:
var list = new CustomList<int> { 1, 2 };
list += 3;
Console.WriteLine(string.Join(", ", list)); // Will print 1, 2, 3

The accepted answer above works better for the question asked, but in addition to that if someone needs to add two lists of any type and preserve the original lists. I should probably have posted this on a different topic, but doing search on "overloading + operator in c#" brings up this as top results. It may help someone hopefully.
void Main()
{
List<string> str = new List<string> {"one", "two", "three"};
List<string> obj = new List<string> {"four", "five", "six", "seven"};
foreach ( string s in str + obj ) Console.Write(s + ", ");
}
public class List<T> : System.Collections.Generic.List<T>
{
public static List<T> operator +(List<T> L1, List<T> L2)
{
List<T> tmp = new List<T>() ;
foreach ( T s in L1 ) tmp.Add(s);
foreach ( T s in L2 ) tmp.Add(s);
return tmp ;
}
}
//one, two, three, four, five, six, seven,

Related

How to iterate thru an array without knowing the underlying type in C#

Let's say I have a collection of objects, some of which are arrays.
I would like to concat all the values to print them, but I don't know the type of elements in the arrays.
foreach(var item in myList)
{
var val = item.Property;
if (val.GetType().IsArray)
{
var array = val as IEnumerable<object>;
val = string.Join(",", array);
}
DoSomething(val);
}
If val contains a string[], this code snippet will work, also for a myClass[].
But if it contains a int[] or double[], then array will be null, meaning the dynamic cast failed.
If int or double are inherited from System.TypeValue, which inherits from object, why don't this code snippet work?
And how could I achieve that?
Edit: changed the code snippet to be more explicit and avoid the wrong variable usage that did showup because I wrongly simplified my code.
It's not allowed to do so in C#, more details here.
But you can cast to non-generic IEnumerable, and then cast everything to object before pushing to string.Join():
foreach(var val in myList)
{
if (val.GetType().IsArray)
{
var array = (IEnumerable)val;
// It's not allowed to set val variable, but I assume it's just an example
val = string.Join(",", array.Cast<object>());
}
}
If you're just worried about arrays in general, or better yet IEnumerable (as per your cast) then I suggest leaving the reflective portion of checks out and simply attempting to convert to IEnumerable.
foreach (var val in myList)
{
if (val is IEnumerable enumeration)
{
string.Join(",", array); //You can't use val (as per your example because it's the element of the loop)
}
}
I honestly don't know what you're intending to do with the array, as your adding it to a string as an object, which will just be array, array, array... and so on pretty much. I'm going to post a better solution however I'm not sure if it's what you want or not because what you're doing above doesn't make a lot of sense.
var notSureWhyStringBuilder = new StringBuilder();
foreach (var val in myList)
{
if (val is IEnumerable enumeration)
{
notSureWhyStringBuilder.Append($",{enumeration.ToString()}");
}
}
Console.WriteLine(notSureWhyStringBuilder.ToString());
Now with this at least I feel like you're more in the direction that you want to be in but that doesn't sit well with me because I don't know what you're going to gain out of it.
I'm going to post one more example, one that will iterate and build the inner enumeration into the string for you. I don't know or assume that's what you want but between the 3 examples I'm providing hopefully you can take away and re-engineer it to get what you need and possibly learn from it.
var notSureWhyStringBuilder = new StringBuilder();
foreach (var val in myList)
{
if (val is IEnumerable enumeration)
{
foreach (var innerEnumeration in enumeration)
{
notSureWhyStringBuilder.Append($",{innerEnumeration.ToString()}");
}
}
}
Console.WriteLine(notSureWhyStringBuilder.ToString());
Here's a small console app that I put together for you to piddle with. Copy and paste it as is and it should work.
Console App
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace Question_Answer_Console_App
{
class Program
{
private const string ShortTab = " ";
private static readonly List<object> ListOfObjects = new List<object>()
{
4,
"Michael",
new object(),
new Program(),
69.4,
new List<string>() {"Mathew", "Mark", "Luke", "John" },
new int[] { 1, 3, 5, 7, 9 }
};
static void Main(string[] args)
{
var itemsText = new StringBuilder();
var arrayCounter = 0;
foreach (var item in ListOfObjects)
{
if (item is IEnumerable enumeration)
{
itemsText.AppendLine($"Array: {++arrayCounter}");
if (item is string text)
{
itemsText.AppendLine($"{ShortTab}{text}");
}
else
{
foreach (var innerItem in enumeration) itemsText.AppendLine($"{ShortTab}{innerItem.ToString()}");
}
}
}
Console.WriteLine(itemsText.ToString());
Console.Read();
}
}
}
Outputs
Array: 1
Michael
Array: 2
Mathew
Mark
Luke
John
Array: 3
1
3
5
7
9
First off, trying to assign to val inside the foreach loop will not work. You can't change a collection you are iterating over.
So you need to build up a new collection. Something like this works, see how the yield return statement in the iterator lets you build up a new IEnumerable of the leaf objects and works for both objects and value types at any level.
class Program
{
static void Main(string[] args)
{
var myWackyList = new object[] {
new[]{1d, 2d},
3d,
new[]{4d, 5d},
new []
{
new[]
{
6d
}
},
"7",
new[]{ "8", "9"}
};
Console.WriteLine( string.Join(", ", Flatten( myWackyList )));
}
static IEnumerable<object> Flatten(IEnumerable enumerable)
{
foreach (var val in enumerable)
{
if ( val.GetType().IsArray )
foreach ( var flattenedVal in Flatten( val as IEnumerable ) )
yield return flattenedVal;
else
yield return val;
}
}
}
You cannot cast a value-type array to an IEnumerable because variance only applies if there's no representational conversion needed. Therefore it doesn't apply for value types. In this particular case this conversion would mean boxing.
I would do it this way to prevent unnecessary boxing, like in the case with Cast, for example.
public static string Stringify(this object o, string delimiter)
{
if (!(o is IEnumerable enumerable))
return o.ToString();
var sb = new StringBuilder();
foreach (var i in enumerable)
{
if (sb.Length > 0)
sb.Append(delimiter);
sb.Append(i.ToString());
}
return sb.ToString();
}

LinkedList generic input

I wrote the folowing method :
// Merge two ArrayLists to the first one without duplication
public static void mergeIntoFirst(ArrayList array1, ArrayList array2)
{
if(array1==null | array2==null)
throw new ArgumentNullException();
if (array1 == array2)
return; //if they are pointing to the same array, then we can exit.
foreach (object obj in array2)
{
if (!array1.Contains(obj))
array1.Add(obj);
}
}
But now I want to change the my program to work with linkedList insted,
because arraylist doesn't work well with linq as far as I know...
But I need the input to be generc, and work with all linked list kind, just like here the ArrayList can contains all sort of objects.
(I'm using this method twice in my code, once with array of users, and the other with array of messages sent by the users)
I thought that using LinkedList<object> will solve it, since anything is object (exept int, chat double itc)
but it throws a casting exeption when running...
what shoul'd I do then?
Thanks!
Here's an implementation of your code that should work for any ICollection<T> of which both LinkedList<T> and List<T> implement. Note that you have to define the generic type on the method.
public static void MergeIntoFirst<T>(ICollection<T> c1, ICollection<T> c2)
{
if(c1==null || c2==null)
throw new ArgumentNullException();
if (c1 == c2)
return; //if they are pointing to the same array, then we can exit.
foreach (T item in c2)
{
if (!c1.Contains(item))
c1.Add(item);
}
}
Then you could use it like this.
List<int> l1 = new List<int> { 1, 2, 3 };
List<int> l2 = new List<int> { 2, 3, 4 };
MergeIntoFirst(l1, l2);
Console.WriteLine(string.Join(",", l1));
// outputs: 1, 2, 3, 4
Note that this is close to what Enumerable.Union does except that it would remove duplicates that exist in both collections and produces a new collection rather than mutating the first one.

How to Create A Merged Array from 3 Arrays with LINQ which is not zipped but based on Content Equality

I have three Arrays which should be merged into one result via Linq:
int?[] list1 = {0,1,2,3,4};
int?[] list2 = {2,3,4,5};
int?[] list3 = {3,4};
Result:
var result=
{
(0,null,null),
(1,null,null),
(2,2,null),
(3,3,3),
(4,4,4),
(null,5,null)
}
Let's start by defining our input in a little more generic terms: a list of a list of integers. Since we don't need to modify these collections, we'll use the simplest interface that gives us what we need, IEnumerable<T>. That means our input is going to be: IEnumerable<IEnumerable<int?>>. Our output is going to be the same.
So now, let's define a prototype for the method that will do the work:
public static IEnumerable<IEnumerable<int?>> Merge(IEnumerable<IEnumerable<int?>> source) { //... }
Immediately I've noticed something: we don't really need to use int? since all we care about is checking equality, and all types support that, so we can make this method generic, and support any type:
public static IEnumerable<IEnumerable<T>> Merge<T>(IEnumerable<IEnumerable<T>> source) { //... }
Now let's start with the implementation, first we will need to compute every distinct value from all the lists:
source.SelectMany(x=>x).Distinct()
Now, for each of those values we need to return a collection with an item for each item in the original 'super list':
source.SelectMany(x=>x).Distinct().Select(x=>source.Select(y=> //...
So what do we need in that final Select lambda? We have x as each distinct integer (or technically T), and y as each original collection. We want the value x if the y collection contains x, otherwise, null (or to allow value types too, default(T). We can do that with a ternary:
source.SelectMany(x=>x).Distinct().Select(x=>source.Select(y=>y.Contains(x)?x:default(T)));
Putting it all together:
public static IEnumerable<IEnumerable<T>> Merge<T>(this IEnumerable<IEnumerable<T>> source)
{
return source
.SelectMany(x=>x)
.Distinct()
.Select(x=>source
.Select(y=>y.Contains(x)?x:default(T)));
}
And you can call it like so:
int?[] list1 = {0,1,2,3,4};
int?[] list2 = {2,3,4,5};
int?[] list3 = {3,4};
var result = new []{ list1, list2, list3 }.Merge();
Console.WriteLine(string.Join(Environment.NewLine, result.Select(t=>string.Join(",", t))));
First put all your arrays into one:
var lists = new[] { list1, list2, list3 };
Now loop all possible numbers and check if check if they are contained in the appropriate arrays. If so, you can add that number to your result, otherwise add null:
var result = new List<List<int?>>();
for(int i = 0; i < 6; i++)
{
result.Add(new List<int?>());
for(int j = 0; j < 3; j++)
{
if(lists[j].Contains(i))
result[i].Add(i);
else
result[i].Add(null);
}
}
I suppose this is pretty straightforward. Doing this is linq will just overcomplicate things, looks ugly and is hard to debug and understand. I doubt it´s a good idea to do so.

Is there a way to define a List<> of two elements string array?

I want to build two-dimentional array of strings where length of one dimention is 2. Similar to this
string[,] array = new string[,]
{
{"a", "b"},
{"c", "d"},
{"e", "f"},
{"g", "h"}
}
Doing
List<string[]> list = new List<string[]>();
list.Add(new string[2] {"a", "b"});
list.Add(new string[2] {"c", "d"});
list.Add(new string[2] {"e", "f"});
list.Add(new string[2] {"g", "h"});
list.ToArray();
gives me
string[][]
but not
string[,]
array.
Just curious, is there some trick to build dynamically
string[,]
array somehow?
You can do this.
List<KeyValuePair<string, string>>
The idea being that the Key Value Pair would mimic the array of strings you replicated.
Well, you could reasonably easily write an extension method to do it. Something like this (only tested very slightly):
public static T[,] ToRectangularArray<T>(this IEnumerable<T[]> source)
{
if (!source.Any())
{
return new T[0,0];
}
int width = source.First().Length;
if (source.Any(array => array.Length != width))
{
throw new ArgumentException("All elements must have the same length");
}
T[,] ret = new T[source.Count(), width];
int row = 0;
foreach (T[] array in source)
{
for (int col=0; col < width; col++)
{
ret[row, col] = array[col];
}
row++;
}
return ret;
}
It's a slight shame that the above code uses T[] as the element type. Due to generic invariance I can't currently make source IEnumerable<IEnumerable<T>> which would be nice. An alternative might be to introduce a new type parameter with a constraint:
public static T[,] ToRectangularArray<T,U>(this IEnumerable<U> source)
where U : IEnumerable<T>
Somewhat hairy, but it should work. (Obviously the implementation needs some changes too, but the basic principle is the same.)
The only way to do it would be to implement the ToArray() function yourself. You could implement it within your own collection (i.e. StringTupleCollection). This could work the same as ArrayList (i.e. internal array increasing in size as needed).
However I'm not sure the advantage of [x,2] over [x][2] (or even List<string[2]> would be significant enough to warrant the effort.
You could also write a StringTupple class as:
public class StringTupple : KeyValuePair<string, string>
{
}
You could just use a struct. I do this when comparing XML Nodes manually.
private struct XmlPair
{
public string Name { set; get; }
public string Value { set; get; }
}
List<XmlPair> Pairs = new List<XmlPair>();
This isn't possible with a List<string[]>, as the type string[,] is different from string[].
KeyValuePair did not work for me when I had to retrieve the values of the checkboxes on the controller as my model.Roles list was null.
foreach (KeyValuePair<string, bool> Role in model.Roles){...}
The KeyValuePair structure doesn't have a default parameterless constructor and can't be instantiated by the model binder. I recommend a custom model class for your view that has just those properties. ASP.NET MVC 3 binding user control of type KeyValuePair to ViewModel
I found an implementation of a checkboxlist without the use of html helper at the following link CheckboxList in MVC3.0

How to iterate over two arrays at once?

I have two arrays built while parsing a text file. The first contains the column names, the second contains the values from the current row. I need to iterate over both lists at once to build a map. Right now I have the following:
var currentValues = currentRow.Split(separatorChar);
var valueEnumerator = currentValues.GetEnumerator();
foreach (String column in columnList)
{
valueEnumerator.MoveNext();
valueMap.Add(column, (String)valueEnumerator.Current);
}
This works just fine, but it doesn't quite satisfy my sense of elegance, and it gets really hairy if the number of arrays is larger than two (as I have to do occasionally). Does anyone have another, terser idiom?
You've got a non-obvious pseudo-bug in your initial code - IEnumerator<T> extends IDisposable so you should dispose it. This can be very important with iterator blocks! Not a problem for arrays, but would be with other IEnumerable<T> implementations.
I'd do it like this:
public static IEnumerable<TResult> PairUp<TFirst,TSecond,TResult>
(this IEnumerable<TFirst> source, IEnumerable<TSecond> secondSequence,
Func<TFirst,TSecond,TResult> projection)
{
using (IEnumerator<TSecond> secondIter = secondSequence.GetEnumerator())
{
foreach (TFirst first in source)
{
if (!secondIter.MoveNext())
{
throw new ArgumentException
("First sequence longer than second");
}
yield return projection(first, secondIter.Current);
}
if (secondIter.MoveNext())
{
throw new ArgumentException
("Second sequence longer than first");
}
}
}
Then you can reuse this whenever you have the need:
foreach (var pair in columnList.PairUp(currentRow.Split(separatorChar),
(column, value) => new { column, value })
{
// Do something
}
Alternatively you could create a generic Pair type, and get rid of the projection parameter in the PairUp method.
EDIT:
With the Pair type, the calling code would look like this:
foreach (var pair in columnList.PairUp(currentRow.Split(separatorChar))
{
// column = pair.First, value = pair.Second
}
That looks about as simple as you can get. Yes, you need to put the utility method somewhere, as reusable code. Hardly a problem in my view. Now for multiple arrays...
If the arrays are of different types, we have a problem. You can't express an arbitrary number of type parameters in a generic method/type declaration - you could write versions of PairUp for as many type parameters as you wanted, just like there are Action and Func delegates for up to 4 delegate parameters - but you can't make it arbitrary.
If the values will all be of the same type, however - and if you're happy to stick to arrays - it's easy. (Non-arrays is okay too, but you can't do the length checking ahead of time.) You could do this:
public static IEnumerable<T[]> Zip<T>(params T[][] sources)
{
// (Insert error checking code here for null or empty sources parameter)
int length = sources[0].Length;
if (!sources.All(array => array.Length == length))
{
throw new ArgumentException("Arrays must all be of the same length");
}
for (int i=0; i < length; i++)
{
// Could do this bit with LINQ if you wanted
T[] result = new T[sources.Length];
for (int j=0; j < result.Length; j++)
{
result[j] = sources[j][i];
}
yield return result;
}
}
Then the calling code would be:
foreach (var array in Zip(columns, row, whatevers))
{
// column = array[0]
// value = array[1]
// whatever = array[2]
}
This involves a certain amount of copying, of course - you're creating an array each time. You could change that by introducing another type like this:
public struct Snapshot<T>
{
readonly T[][] sources;
readonly int index;
public Snapshot(T[][] sources, int index)
{
this.sources = sources;
this.index = index;
}
public T this[int element]
{
return sources[element][index];
}
}
This would probably be regarded as overkill by most though ;)
I could keep coming up with all kinds of ideas, to be honest... but the basics are:
With a little bit of reusable work, you can make the calling code nicer
For arbitrary combinations of types you'll have to do each number of parameters (2, 3, 4...) separately due to the way generics works
If you're happy to use the same type for each part, you can do better
if there are the same number of column names as there are elements in each row, could you not use a for loop?
var currentValues = currentRow.Split(separatorChar);
for(var i=0;i<columnList.Length;i++){
// use i to index both (or all) arrays and build your map
}
In a functional language you would usually find a "zip" function which will hopefully be part of a C#4.0 . Bart de Smet provides a funny implementation of zip based on existing LINQ functions:
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
this IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
Func<TFirst, TSecond, TResult> func)
{
return first.Select((x, i) => new { X = x, I = i })
.Join(second.Select((x, i) => new { X = x, I = i }),
o => o.I,
i => i.I,
(o, i) => func(o.X, i.X));
}
Then you can do:
int[] s1 = new [] { 1, 2, 3 };
int[] s2 = new[] { 4, 5, 6 };
var result = s1.Zip(s2, (i1, i2) => new {Value1 = i1, Value2 = i2});
If you're really using arrays, the best way is probably just to use the conventional for loop with indices. Not as nice, granted, but as far as I know .NET doesn't offer a better way of doing this.
You could also encapsulate your code into a method called zip – this is a common higher-order list function. However, C# lacking a suitable Tuple type, this is quite crufty. You'd end up returning an IEnumerable<KeyValuePair<T1, T2>> which isn't very nice.
By the way, are you really using IEnumerable instead of IEnumerable<T> or why do you cast the Current value?
Use IEnumerator for both would be nice
var currentValues = currentRow.Split(separatorChar);
using (IEnumerator<string> valueEnum = currentValues.GetEnumerator(), columnEnum = columnList.GetEnumerator()) {
while (valueEnum.MoveNext() && columnEnum.MoveNext())
valueMap.Add(columnEnum.Current, valueEnum.Current);
}
Or create an extension methods
public static IEnumerable<TResult> Zip<T1, T2, TResult>(this IEnumerable<T1> source, IEnumerable<T2> other, Func<T1, T2, TResult> selector) {
using (IEnumerator<T1> sourceEnum = source.GetEnumerator()) {
using (IEnumerator<T2> otherEnum = other.GetEnumerator()) {
while (sourceEnum.MoveNext() && columnEnum.MoveNext())
yield return selector(sourceEnum.Current, otherEnum.Current);
}
}
}
Usage
var currentValues = currentRow.Split(separatorChar);
foreach (var valueColumnPair in currentValues.Zip(columnList, (a, b) => new { Value = a, Column = b }) {
valueMap.Add(valueColumnPair.Column, valueColumnPair.Value);
}
Instead of creating two seperate arrays you could make a two-dimensional array, or a dictionary (which would be better). But really, if it works I wouldn't try to change it.

Categories