Issues with concatenating after Array.Select in C# - c#

I'm working on the following code for a uni project:
public Order[] collapse()
{
return ConcatArrays(Rondes.Select(rs => rs.collapse()));
}
public static T[] ConcatArrays<T>(T[][] list)
{
var result = new T[list.Sum(a => a.Length)];
int offset = 0;
for (int x = 0; x < list.Length; x++)
{
list[x].CopyTo(result, offset);
offset += list[x].Length;
}
return result;
}
Here rs is of a custom type Ronde, and rs.collapse() returns Order[]. The goal of the first function is to compute rs.collapse() for every rs, and concatenate these arrays. How do I resolve the following error:
The type arguments for method ConcatArrays<T>(T[][]) cannot be inferred from the usage. Try specifying the type arguments explicitly.
I tried to follow the reccomendation by changing all T's to Order, but that did not change the error message. Any help is greatly appreciated!! Thanks in advance!
EDIT:
I have now changed the first function to:
public Order[] collapse()
{
if (Rondes == null) { return new Order[0]; }
return OrderLijsten.ConcatArrays<Order>(Rondes.Select(rs => rs.collapse()));
}
but now i get this error:
Error CS1503 Argument 1: cannot convert from 'System.Collections.Generic.IEnumerable<Grote_Opdracht.Classes.Order[]>' to 'Grote_Opdracht.Classes.Order[][]'

The error message gives you a pretty clear explanation: Your Select call returns an IEnumerable but this ConcatArrays implementation expects an array (of arrays).
You could either make the method use IEnumerable (but then you would enumerate multiple times), or call ToArray to make an array. In this case, I would prefer a combination, and also use ToList instead, which should be the most performant option:
public Order[] Collapse()
{
// make sure to iterate only once
var arrays = Rondes.Select(rs => rs.collapse()).ToList();
return ConcatArrays(arrays);
}
// use IEnumerable to be more flexible
public static T[] ConcatArrays<T>(IEnumerable<T[]> arrays)
{
var result = new T[arrays.Sum(a => a.Length)];
int offset = 0;
foreach (var a in arrays)
{
a.CopyTo(result, offset);
offset += a.Length;
}
return result;
}

Related

Why do i get: "Error 2 Argument 1: cannot convert from 'int' to 'TRAINING1.Node<int>' " error?

this is a function that is supposed to take a list and reverse it. i do not know why i get this error.
public static void What(List<int> lst)
{
Stack<int> st1 = new Stack<int>();
while (!lst.IsEmpty())
{
**st1.Push(lst.Remove(lst.GetFirst().GetInfo());**
}
Node<int> pos = lst.GetFirst();
while (!st1.IsEmpty())
{
pos = lst.Insert(pos, st1.Pop());
}
}
st1 is a Stack<int>, which means that it is a strongly-typed stack of ints. You cannot add Node<int> to this list, if the is no implicit convertion from Node<int> to int. Anyway, try to use next code as an example of working with stack:
public static void Reverse(List<int> lst)
{
Stack<int> st1 = new Stack<int>();
while (lst.Count != 0)
{
var item = lst[0];
lst.RemoveAt(0);
st1.Push(item);
}
while (st1.Count != 0)
{
lst.Add(st1.Pop());
}
}
This is not an efficient solution and has a huge amount of drawbacks. I just want to illustrate correct reversing method using stack as close as possible to your case.
You can make method Reverse generic, but the are already implemented behavior in Linq.
Consider using Reverse Linq method. If you want just to reverse List<int>, use myList.Reverse().ToList(). It will return the same List<int> but in reversed order.

Automatic unboxing

I have an array of objects (object[]). All the items in this array have the same type (unknown at compile time). I need to convert this array in a typed array, that is, if the items are integers, I want to get an int[].
I've looked into the Array.ConvertAll method, but I need to specify a specific type in the template, meaning that I have to get the element type then call ConvertAll for each case possible.
I've also looked into the keyword dynamic with no more luck (looks like dynamic[] is the same as object[]).
How can I achieve this?
It sounds like you want something like:
dynamic array = Array.CreateInstance(input[0].GetType(), input.Length);
for (int i = 0; i < input.Length; i++)
{
array[i] = (dynamic) input[i];
}
Here the dynamic just handles the conversion part for you.
Alternatively:
public static Array ConvertArray(object[] input)
{
dynamic sample = input[0]; // Just used for type inference
return ConvertArrayImpl(sample, input);
}
private static T[] ConvertArrayImpl<T>(T sample, object[] input)
{
return input.Cast<T>().ToArray();
}
You could do make the ConvertArrayImpl call with reflection manually of course, instead of using dynamic typing.
Also note that all of these will fail if the input array is empty...
Similar to Jon's solution you can do without dynamic and make use of the Array type:
public Array Convert(Array a) {
if (a.GetLength(0) == 0){
return new int[0];
}
var type = a.GetValue(0).GetType();
var result = Array.CreateInstance(type, a.GetLength(0));
for (int i = 0; i < a.GetLength(0); i++) {
result.SetValue(a.GetValue(i), i);
}
return result;
}

Way to pad an array to avoid index outside of bounds of array error

I expect to have at least 183 items in my list when I query it, but sometimes the result from my extract results in items count lower than 183. My current fix supposedly pads the array in the case that the count is less than 183.
if (extractArray.Count() < 183) {
int arraysize= extractArray.Count();
var tempArr = new String[183 - arraysize];
List<string> itemsList = extractArray.ToList<string>();
itemsList.AddRange(tempArr);
var values = itemsList.ToArray();
//-- Process the new array that is now at least 183 in length
}
But it seems my solution is not the best. I would appreciate any other solutions that could help ensure I get at least 183 items whenever the extract happens please.
I'd probably follow others' suggestions, and use a list. Use the "capacity" constructor for added performance:
var list = new List<string>(183);
Then, whenever you get a new array, do this (replace " " with whatever value you use to pad the array):
list.Clear();
list.AddRange(array);
// logically, you can do this without the if, but it saves an object allocation when the array is full
if (array.Length < 183)
list.AddRange(Enumerable.Repeat(" ", 183 - array.Length));
This way, the list is always reusing the same internal array, reducing allocations and GC pressure.
Or, you could use an extension method:
public static class ArrayExtensions
{
public static T ElementOrDefault<T>(this T[] array, int index)
{
return ElementOrDefault(array, index, default(T));
}
public static T ElementOrDefault<T>(this T[] array, int index, T defaultValue)
{
return index < array.Length ? array[index] : defaultValue;
}
}
Then code like this:
items.Zero = array[0];
items.One = array[1];
//...
Becomes this:
items.Zero = array.ElementOrDefault(0);
items.One = array.ElementOrDefault(1);
//...
Finally, this is the rather cumbersome idea with which I started writing this answer: You could wrap the array in an IList implementation that's guaranteed to have 183 indexes (I've omitted most of the interface member implementations for brevity):
class ConstantSizeReadOnlyArrayWrapper<T> : IList<T>
{
private readonly T[] _array;
private readonly int _constantSize;
private readonly T _padValue;
public ConstantSizeReadOnlyArrayWrapper(T[] array, int constantSize, T padValue)
{
//parameter validation omitted for brevity
_array = array;
_constantSize = constantSize;
_padValue = padValue;
}
private int MissingItemCount
{
get { return _constantSize - _array.Length; }
}
public IEnumerator<T> GetEnumerator()
{
//maybe you don't need to implement this, or maybe just returning _array.GetEnumerator() would suffice.
return _array.Concat(Enumerable.Repeat(_padValue, MissingItemCount)).GetEnumerator();
}
public int Count
{
get { return _constantSize; }
}
public bool IsReadOnly
{
get { return true; }
}
public int IndexOf(T item)
{
var arrayIndex = Array.IndexOf(_array, item);
if (arrayIndex < 0 && item.Equals(_padValue))
return _array.Length;
return arrayIndex;
}
public T this[int index]
{
get
{
if (index < 0 || index >= _constantSize)
throw new IndexOutOfRangeException();
return index < _array.Length ? _array[index] : _padValue;
}
set { throw new NotSupportedException(); }
}
}
Ack.
The Array base class implements the Resize method
if(extractArray.Length < 183)
Array.Resize<string>(ref extractArray, 183);
However, keep in mind that resizing is problematic for performance, thus this method is useful only if you require the array for some reason. If you can switch to a List
And, I suppose you have an unidimensional array of strings here, so I use the Length property to check the effective number of items in the array.
Since you've stated that you need to ensure there's 183 indexes, and that you need to pad it if there is not, I would suggest using a List instead of an array. You can do something like:
while (extractList.Count < 183)
{
extractList.Add(" "); // just add a space
}
If you ABSOLUTELY have to go back to an array you can using something similar.
I can't say that I would recommend this solution, but I won't let that stop me from posting it! Whether they like to admit it or not, everyone likes linq solutions!
Using linq, given an array with X elements in it, you can generate an array with exactly Y (183 in your case) elements in it like this:
var items183exactly = extractArray.Length == 183 ? extractArray :
extractArray.Take(183)
.Concat(Enumerable.Repeat(string.Empty, Math.Max(0, 183 - extractArray.Length)))
.ToArray();
If there are fewer than 183 elements, the array will be padded with empty strings. If there are more than 183 elements, the array will be truncated. If there are exactly 183 elements, the array is used as is.
I don't claim that this is efficient or that it is necessarily a good idea. However, it does use linq (yippee!) and it is fun.

Consuming an Array returned from a Method

from my function below, I am returning an array. In C# how would I consume that array?
public Array arrayFucntion()
{
// do something
foreach (var Objs in items)
{
list.Add(Objs.value1);
}
string[] myArray = list.ToArray();
MessageBox.Show(myArray.ToString());
return myArray;
}
Now how would I use it in a function like below
void consumeFunction()
{
var x = arrayFucntion();
// what do do to see values of the array
}
Return a string[], then you can do the for loop through the string array.
public string[]arrayFucntion()
void consumeFunction()
{
var x = arrayFucntion();
for (int i=0; i<x.Lenght; i++)
{
x[i]...
}
}
Make the return type string[] instead of Array.
You can iterate through the members:
foreach (string sArrayMember in x)
{
// Do something with s
}
You can also access any of the properties or members listed in the MSDN documentation, including Copy, Find, and Sort.
x is now an array object...
you can do foreach on it, or use linq.....or using direct addressing x[0]

C#: Convert T to T[]

I would like to convert T to T[] if it is an array.
static T GenericFunction<T>(T t)
{
if (t == null) return default(T);
if (t.GetType().IsArray)
{
//if object is an array it should be handled
//by an array method
return (T) GenericArrayFunction((T[])t);
}
...
}
static T[] GenericArrayFunction<T>(T[] t)
{
if (t == null) return default(T);
for (int i = 0 ; i < t.Length ; i++)
{
//for each element in array carry
//out Generic Function
if (t[i].GetType().IsArray())
{
newList[i] = GenericArrayFunction((T[])t[i]);
}
else
{
newList[i] = GenericFunction(t[i]);
}
}
...
}
Error If I try (T[])t
Cannot convert type 'T' to 'T[]'
Error If I just try to pass t
The type arguments for method 'GenericArrayFunction(T[])' cannot be inferred from the usage. Try specifying the type arguments explicitly.
Judging from your particular example, could you not define two methods and let the compiler choose the correct one when an array is passed in?
using System;
class Program
{
static T GenericFunction<T>(T t)
{
Console.WriteLine("GenericFunction<T>(T)");
return default(T);
}
static T[] GenericFunction<T>(T[] t)
{
// Call the non-array function
for(int i = 0; i < t.Length; ++i)
t[i] = GenericFunction(t[i]);
Console.WriteLine("GenericFunction<T>(T[])");
return new T[4];
}
static void Main()
{
int[] arr = {1,2,3};
int i = 42;
GenericFunction(i); // Calls non-array version
GenericFunction(arr); // Calls array version
}
}
Just because T is an array type doesn't mean that it's also an array of T. In fact, the only way that could happen would be for T to be something like object, Array or one of the interfaces implemented by arrays.
What are you really trying to do? I suspect you want to find out the element type of the array, and then call GenericArrayFunction with the appropriate T - but that won't be the same T, and you'll need to call it with reflection, which will be somewhat painful. (Not too bad, but unpleasant.)
I suspect you don't fully understand C#/.NET generics - please give us more context about the bigger picture so we can help you better.
EDIT: The reflection approach would be something like this:
private static readonly ArrayMethod = typeof(NameOfContainingType)
.GetMethod("GenericArrayFunction", BindingFlags.Static | BindingFlags.NonPublic);
...
static T GenericFunction<T>(T t)
{
if (t == null) return default(T);
if (t is Array)
{
Type elementType = t.GetType().GetElementType();
MethodInfo method = ArrayMethod.MakeGenericMethod(new[] elementType);
return (T) method.Invoke(null, new object[] { t });
}
...
}
Note that this will still fail for rectangular arrays, which get even harder to cope with.
It is not possible. T can never be T[]. T is always certain type, not just placeholder. If T is array (int[]) then T[] will be int[][].
Edit: There are some exceptions (like object is object[]), but in general case (and thats what generics are) T can't be T[]

Categories

Resources