C# ValueTuple of any size - c#

Is it possible to write a C# method that accepts a value tuple with any number of items of the same type and converts them into a list?
Edit 2/6/2019
I accepted the Provided answer as the correct one. I wanted to also provide a solution that uses a base class that is not an interface, becuase I am trying to write a conversion operator and user defined conversions from an interface are not allowed.
public static class TupleExtensions
{
public static IEnumerable<object> Enumerate(this ValueType tpl)
{
var ivt = tpl as ITuple;
if (ivt == null) yield break;
for (int i = 0; i < ivt.Length; i++)
{
yield return ivt[i];
}
}
}

You can use the fact that ValueTuples implement the ITuple interface.
The only issue is that tuple elements can be of arbitrary type, so the list must accept any kind of type.
public List<object> TupleToList(ITuple tuple)
{
var result = new List<object>(tuple.Length);
for (int i = 0; i < tuple.Length; i++)
{
result.Add(tuple[i]);
}
return result;
}
This also works as an extension method:
public static class ValueTupleExtensions
{
public static List<object> ToList(this ITuple tuple)
{
var result = new List<object>(tuple.Length);
for (int i = 0; i < tuple.Length; i++)
{
result.Add(tuple[i]);
}
return result;
}
}
This way it is possible to write var list = (123, "Text").ToList();.
Edit 2020-06-18: If every element of the tuple is of the same type it's possible to create list with the proper element type:
public List<T> TupleToList<T>(ITuple tuple)
{
var result = new List<T>(tuple.Length);
for (int i = 0; i < tuple.Length; i++)
{
result.Add((T)tuple[i]);
}
return result;
}

Related

Creating an IEnumerable<> from a generator method using a factory function

I have a factory function, and want to use it to create an Enumerable. In C# I didn't find a straight-forward declarative way to do the job. So I did it like this:
public IEnumerable<Contact> Get()
{
return Enumerable.Range(1, 5).Select(x => GenerateRandomContact());
}
Is there any better way?
// Expected format
public IEnumerable<Contact> Get()
{
return Enumerable.Generate(GenerateRandomContact).Take(5);
}
Something like:
public static IEnumerable<T> Generate(Func<T> generator)
{
while(true)
yield return generator.Invoke();
}
But you can't extend static classes. So you should place it in a helper class.
public IEnumerable<Contact> Get()
{
for(int i = 1; i <= 5; i ++)
{
yield return GenerateRandomContact();
}
}
or if you want a specific amount you can do this
public IEnumerable<Contact> Get(int number)
{
for(var i = 1; i <= number; i ++) //is the same as for (var i = 1;; i++) you got the idea
{
yield return GenerateRandomContact();
}
}
You are expecting something like Enumerable.Generate()
In order to get a list of elements that you want to Enumerate, your Generate method should return an Enumerable Value. You are trying to create an extension method for Enumerable based on your approach. Before that try to see the implementation of Range
public static IEnumerable<int> Range(int start, int count)
{
long max = ((long)start) + count - 1;
if (count < 0 || max > Int32.MaxValue) throw Error.ArgumentOutOfRange("count");
return RangeIterator(start, count);
}
static IEnumerable<int> RangeIterator(int start, int count)
{
for (int i = 0; i < count; i++) yield return start + i;
}
In that case with the yield, .NET creates the IEnumerable class for you and based on a specific amount. Maybe you should consider passing the amount on the Generate method, or like the other extensions as Concat, you should pass the IEnumerable, see bellow how they pass to the Contact mehotd the IEnumerable first variable
public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second)
{
if (first == null) throw Error.ArgumentNull("first");
if (second == null) throw Error.ArgumentNull("second");
return ConcatIterator<TSource>(first, second);
}
With that said.
You can use my first approach or your GenerateRandomContact should return an IEnumerable of Contact, but there is the problem, how much elements you want on that Random creation, or you don't specify the amount as bellow
public IEnumerable<Contact> GenerateRandomContact()
{
var random = new Random(Environment.TickCount);
for (int i = 0; i < 100; i++)
{
yield return new Contact
{
Name = $"Name_{random.Next()}"
};
}
}
or you pass the parameter
But the whole problem now is, if you want to call your method as Enumerable.Generate, that is not possible, You can't have extension methods on static classes because extension methods are only applicable to instantiable types and static classes cannot be instantiated.
Your call should be
IEnumerable<Contact> contacts = new List<Contact>(){....}
//where contacts is an instance of type
contacts.Generate
even in the case you want this syntax
contacts.Generate(GenerateRandomContact).Take(5);
your extension method should accept a function but here I am relying on the previous GenerateRandomContact() where I put 100 random contacts
public static class Extension
{
public static IEnumerable<T> Generate<T>(this IEnumerable<T> elements, Func<IEnumerable<T>> func)
{
if (func != null)
{
return func();
}
return Enumerable.Empty<T>();
}
}
IMHO try to consider passing the amount that you want to take. Your syntax will change a little bit
class Program
{
static void Main(string[] args)
{
IEnumerable<Contact> contacts = new List<Contact>()
{
new Contact
{
Name = "Name1"
},
new Contact
{
Name = "Name2"
}
}; //load your methods from the database or create them here
var res = contacts.Generate(GenerateRandomContact, 5);
Console.ReadLine();
}
static IEnumerable<Contact> GenerateRandomContact(int amount)
{
var random = new Random(Environment.TickCount);
for (int i = 0; i < amount; i++)
{
yield return new Contact
{
Name = $"Name_{random.Next()}"
};
}
}
}
public class Contact
{
public string Name { get; set; }
}
public static class Extension
{
public static IEnumerable<T> Generate<T>(this IEnumerable<T> elements, Func<int, IEnumerable<T>> func, int amount)
{
if (func != null)
{
return func(amount);
}
return Enumerable.Empty<T>();
}
}
}

passing an array without being a copy c#

How can i pass an array without making a copy of it?
I have:
private readonly IList<GameObjectTemplate> mMapGameObjects;
public GameObjectTemplate[] GetObjects(GameObjectType type)
{
List<GameObjectTemplate> tempObjects = new List<GameObjectTemplate>();
for (int i = 0; i < mMapGameObjects.Count; i++)
{
if (mMapGameObjects[i].Type == type)
{
tempObjects.Add(mMapGameObjects[i]);
}
}
return tempObjects.ToArray();
}
So i want to select only my objects of a certain type and return the same array without being a copy.Is it possible?
Unless you really need an array as result consider returning IEnumerable<GameObjectTemplate>:
public IEnumerable<GameObjectTemplate> GetObjects(GameObjectType type)
{
return mMapGameObjects.Where(m => m.Type == type);
}

Array index return null instead of out of bound

I am currently trying to implement an "indexed" property within my class definition.
For example I have the following class:
public class TestClass
{
private int[] ids = null;
public string Name { get; set; }
public string Description { get; set; }
public int[] Ids {
get
{
//Do some magic and return an array of ints
//(count = 5 - in this example in real its not fixed)
return _ids;
}
}
}
Now I like to use this class as the following:
private void DoSomething()
{
var testClass = GetSomeTestClass();
//work with the ids
for (int i = 0; i < 10; i++) //I know I could say i < Ids.Length, its just an example
{
int? id = testClass.Ids[i];
//this will result, in a out of bound exception when i reaches 5 but I wish for it to return a null like a "safe" index call ?!?
}
}
So is there a safe index call that results in a null, without the need for me to wrap it again and again in a try catch.
Another thing I dont wish to use the class index, because I need several properties that work like this, with different types (int, string, bool, custom class and so on).
(Again the for is just a simple example, I know I could in this case say "i < Ids.Length")
If you were only interested in already non-nullable type data e.g. struct you could have gotten away with a simple extension method e.g.
public static class ArrayExt
{
public static Nullable<T> GetValueOrNull(this T[] array, int index) where T: struct
{
return array.Length < index ? new Nullable<T>(array[index]) : null;
}
}
which would have allowed you to simply call
int? id = testClass.Ids.GetValueOrNull(i);
However, given you need to support an arbitrary number of types my suggestion would be to implement a wrapper around an array and take control over how you access the data e.g.
public class SafeArray<T>
{
private T[] items;
public SafeArray(int capacity)
{
items = new T[capacity];
}
public object this[int index]
{
get
{
return index < items.Length ? (object)items[index] : null;
}
set
{
items[index] = (T)value;
}
}
}
public class TestClass
{
public TestClass()
{
Ids = new SafeArray<int>(5);
Instances = new SafeArray<MyClass>(5);
}
...
public SafeArray<int> Ids { get; private set; }
public SafeArray<MyClass> Instances { get; private set; }
}
The key to this approach is to use object as the return type. This allows you to cast (or box/unbox if using value types) the data to the expected type on the receiving end e.g.
for (int i = 0; i < 10; i++)
{
// we need an explicit cast to un-box value types
var id = (int?)testClass.Ids[i];
// any class is already of type object so we don't need a cast
// however, if we want to cast to original type we can use explicit variable declarations e.g.
MyClass instance = testClass.Instances[i];
}
OK, whole new approach. Since you have several possible types and want a "joker" method, you can store the values as key/value collection in your class then such method becomes possible.
First, to store the values internally:
public class TestClass
{
private Dictionary<Type, Array> _values = new Dictionary<Type, Array>();
}
Now to populate that collection with actual data:
_values.Add(typeof(int?), new int[] { 1, 2, 3 });
_values.Add(typeof(string), new string[] { "a", "b", "c", "d", "e" });
And finally the joker method:
public T Get<T>(int index)
{
Type type = typeof(T);
Array array;
if (_values.TryGetValue(type, out array))
{
if (index >= 0 && index < array.Length)
{
return (T)array.GetValue(index);
}
}
return default(T);
}
Usage:
for (int i = 0; i < 10; i++)
{
int? id = testClass.Get<int?>(i);
string name = testClass.Get<string>(i);
//...
}
There's really not much else you can do here than just:
if (i >= array.Length) return null;
else return array[i];
or, using the ? operator:
return (i >= array.Length) ? null : array[i];
You could use method instead of property:
public int? Ids(int i) {
if (i >= 0 && i < _ids.length)
{
return _ids[i];
}
return null;
}
from what I have read I see you are implemet a property of an array type, but not an indexer
it is kind of a moveton to fake index out of range situation and it would be still much much better if you take in your code care about out of range. at the end of the day nobody prevent you on assigning a default (in your case NULL) value when range is violated
if you need a shortcut for your the situation you have described above, I would go for the following method in your class:
public int? ReadAtOrNull(int index)
{
return index < ids.Lenght && index > 0 ? (int?)ids[index] : null;
}
People may start complaining that this may be an overhead, but what if you used Skip and FirstOrDefault?
for (int i = 0; i < 10; i++) //I know I could say i < Ids.Length, its just an example
{
int? id = testClass.Ids.Skip(i).FirstOrDefault();
}
Mind you that in this case you may need to declare your array as int?[] otherwise the default value is 0 instead of null.
please Try :
for (int i = 0; i < Ids.Length; i++)
{
if (!String.IsNullOrEmpty(testClass.Ids[i].Tostring())
int? id = testClass.Ids[i];
}
It seems like the think to do here is to use a class index. Here is a direct answer for your TestClass example.
You could also derive your own custom collection class strictly for Ids that stores an int[] internally and overrides all the appropriate access calls I.e) Add, Remove, etc.. (and index the collection like this to make using it easier). Then you could have a property named Ids in your TestClass that behaves like the example.
I know this question is 3 months old but I hope this still helps.
public class TestClass {
private int[] ids = new int[] { 1, 2, 3, 4, 5 };
public string Name { get; set; }
public string Description { get; set; }
public int? this[int index] {
get {
if (index < 0 || index > ids.Length - 1)
return null;
return ids[index];
}
set {
if (value == null)
throw new ArgumentNullException(
"this[index]",
"Ids are not nullable"
);
ids[index] = (int)value;
}
}
}
Usage:
private void DoSomething() {
TestClass testClass = new TestClass();
for (int i = 0; i < 10; i++) {
int? id = testClass[i];
}
// You can assign to the Ids as well
testClass[0] = 6;
}

Remove an item from generic Array C#

I have a generic class defined like this
class MyGenericClass<T> where T : ICompareable
{
T[] data;
public AddData(T[] values)
{
data = values;
}
}
In mainForm, I create 3 random numbers, and add them as values, lets say 1, 2 and 3. So my T[] data; will look like this: [0]1 [1]2 [2]3
What I want to do is to remove 1 of these values from the array, how do I do that when I'm using generics. Lets say I want to remove 3 from the array so it would look like this[0]1 [1]2
Why don't you use a generic List (List<T>) instead of the array as a private member of your class to hold the data ?
As it is a private member, the 'outside world' cannot access the list, and you will have a much easier life since a List allows you to Add and Remove items easily.
class MyGenericClass<T> where T : ICompareable
{
private List<T> data = new List<T>();
public AddData(params T[] values)
{
data.AddRange (values);
}
public RemoveData( T value )
{
data.Remove (value);
}
public RemoveData( params T[] values )
{
for( int i = 0; i < values.Length; i++ )
{
data.Remove (values[i]);
}
}
}
Once you've done this, you can use the Add member-method of the List to add items, and the Remove member method to remove items. Simple as that.
I've used the params keyword in the AddData method so that you can do this:
var x = new MyGenericClass<int>();
x.AddData(1);
x.AddData(2, 3, 4);
x.AddData(somIntegerList.ToArray());
Change your class to look like this (I also implemented Frederik's suggestion of using a List instead of a array.
class MyGenericClass<T> where T : ICompareable
{
List<T> data;
public AddData(T value)
{
data.Add(value);
}
public RemoveData(T value)
{
data.Remove(value);
}
}
If for some reasaon, you insist on using an array, the remove method may look something like this
public RemoveData(T value)
{
data = data.Where( e => e.CompareTo(value) != 0).ToArray();
}
I kind of had the same question, because I was writing a dynamically sized array to practice creating generic classes.
I found that you can either: move all of the elements down and then set the last element equal to default(T), or create a new array of size-1 to be filled with the remaining elements.
Ex:
public class Array<T>
{
private T[] _array { get; set; }
private int _max { get; set; }
private int _size { get; set; }
public Array()
{
_max = 10;
_array = new T[_max];
_size = 0;
}
public T Remove(int i)
{
if (i >= _size || i < 0) return default(T);
var tmp = _array[i];
for (var j = i; j < _size-1; ++j)
{
_array[j] = _array[j + 1];
}
_array[_size - 1] = default(T);
_size--;
return tmp;
}
}
Or...
public T Remove(int i) {
var tmp = new T[_size-1];
for(var j=0; j < i; ++j)
{
tmp[j] = _array[j];
}
var result = _array[i];
for(var j=i+1; j < _size-1; ++j)
{
tmp[j] = _array[j];
}
_array = null;
_array = tmp;
return result;
}

Pivoting a collection of arrays

Basically, I have a collection of objects each implement a member of Type IValueCollection.
public interface IValueCollection : IEnumerable<decimal>
{
decimal this[int index] { get; set; }
}
MeasurementCollection.Values is of type IValueCollection.
With the logic below I want to pivot a collection of IValueCollection and wrote the extension method below.
public static IEnumerable<IValueCollection> PivotValues(this MeasurementCollection items)
{
if(items.IsQuantized())
{
int s = (int)items.First().Template.Frequency;
int c = items.Count;
for (int n = 0; n < s; n++)
{
IValueCollection v = new MeasurementValueCollection(c);
for (int m = 0; m < c; m++)
v[m] = items.ElementAt(m).Values[n];
yield return v;
}
}
}
should do
{{1,2,3}{4,5,6}{7,8,9}} results in {{1,4,7},{2,5,8},{3,6,9}}
However I think there is some nicer, slimmer and more readable expression to do this
can somebody point me in the right direction?
edit
info about underlying classes
interface IValueCollection : IEnumerable<decimal>
class MeasurementCollection : ICollection<IMeasurement>
interface IMeasurement
{
IMeasurementTemplate Template { get; }
......
}
interface IMeasurementTemplate
{
.....
MeasurementFrequency Frequency { get; }
}
I would, personally, force the evaluation of your collection in advance, and use it as an array. Right now, each time you call ElementAt, you're going to evaluate the IEnumerable<T> again, causing a lot of repeated searching.
By forcing it to evaluate to an array in advance, you simplify the entire process. Something like:
public static IEnumerable<IValueCollection> PivotValues(this MeasurementCollection items)
{
if(items.IsQuantized())
{
int elementLength = (int)items.First().Template.Frequency;
var itemArray = items.ToArray();
for (int n = 0; n < itemArray.Length; n++)
{
IValueCollection v = new MeasurementValueCollection(elementLength);
for (int m = 0; m < elementLength; m++)
{
v[m] = itemArray[m].Values[n];
}
yield return v;
}
}
else
yield break; // Handle the case where IsQuantized() returns false...
}
If you control MeasurementValueCollection, I would add a constructor which takes an IEnumerable<decimal> as input, as well. You could then do:
public static IEnumerable<IValueCollection> PivotValues(this MeasurementCollection items)
{
if(items.IsQuantized())
{
var elements = Enumerable.Range(0, (int)items.First().Template.Frequency);
var itemArray = items.ToArray();
foreach(var element in elements)
yield return new MeasurementValueCollection(
itemArray.Select(
(item,index) => itemArray[index].Value[element]
)
);
}
else
yield break; // Handle the case where IsQuantized() returns false...
}

Categories