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]
Related
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;
}
I am trying to call a function which returns a tuple with two arrays. The content of the arrays are based on checked items in a checkedListBox.
I define the arrays and call the function "storeParametersInArrays" as shown below.
string[] allowedObjects = new string[checkedListObjects.CheckedItems.Count]; // All allowed objects
string[] notallowedObjects = new string[checkedListObjects.Items.Count - checkedListObjects.CheckedItems.Count]; // All not allowed objects
Tuple<string[], string[]> ObjParameters = storeParametersInArrays(notallowedObjects, allowedObjects, checkedListObjects);
allowedObjects = ObjParameters.Item1;
notallowedObjects = ObjParameters.Item2;
The function called is defined as:
private Tuple<string[], string[]> storeParametersInArrays(string[] notallowed, string[] allowed, CheckedListBox checkedListBox)
{
int i = 0; // allowed objects
int j = 0; // not allowed objects
int k = 0; // item counter
foreach (object item in checkedListBox.Items)
{
if (!checkedListBox.CheckedItems.Contains(item))
{
notallowed[j++] = checkedListBox.Items[k].ToString();
}
else
{
allowed[i++] = checkedListBox.Items[k].ToString();
}
k++;
}
return Tuple.Create<allowed, notallowed>;
}
I am unable to return the Tuple in the above code sample. I get the error "Cannot convert method group 'Create' to non-delegate type 'Tuple'".
It is my first time working with tuples, how can I return the two arrays without having to call the function twice?
I have looked at slightly similar problems, so if the question is already answered somewhere else, I will be glad to be pointed in the right direction.
Just change
return Tuple.Create<allowed, notallowed>;
to
return Tuple.Create(allowed, notallowed);
The first syntax is for generics: <
The second for method calls: (
You have to correct your method call Tuple.Create:
private Tuple<string[], string[]> storeParametersInArrays(string[] notallowed, string[] allowed, CheckedListBox checkedListBox)
{
int i = 0; // allowed objects
int j = 0; // not allowed objects
int k = 0; // item counter
foreach (object item in checkedListBox.Items)
{
if (!checkedListBox.CheckedItems.Contains(item))
{
notallowed[j++] = checkedListBox.Items[k].ToString();
}
else
{
allowed[i++] = checkedListBox.Items[k].ToString();
}
k++;
}
return Tuple.Create(allowed, notallowed);
}
This line
return Tuple.Create<allowed, notallowed>;
replace with
return Tuple.Create<string[], string[]>(allowed, notallowed);
Or simple
return Tuple.Create(allowed, notallowed);
The static method Create is a generic method and the error is that you are using the values like the types that the Create method will return.
You placed the values where the type parameters should be. But I think that the type parameters can be inferred here:
return Tuple.Create(allowed, notallowed);
However, you could use new ValueTuples. A simplified tuple syntax was introduced in C# 7.0.
private (string[], string[]) storeParametersInArrays(
string[] notallowed, string[] allowed, CheckedListBox checkedListBox)
{
...
return (allowed, notallowed);
}
You can then get the result stored directly into your existing variables with:
(allowedObjects, notallowedObjects) = storeParametersInArrays(
notallowedObjects, allowedObjects, checkedListObjects);
But since arrays are reference types, you don't even have to return them from the method. You are not passing copies of the arrays to the method - only references. Therefore the method fills the original arrays.
private void storeParametersInArrays(
string[] notallowed, string[] allowed, CheckedListBox checkedListBox)
{
// Fill the arrays here.
// No need for a return statement.
}
Now you can write
storeParametersInArrays(notallowedObjects, allowedObjects, checkedListObjects);
// allowedObjects and notallowedObjects are now filled. Example
string firstAllowed = allowedObjects[0];
You can even go a step further and use the Local functions introduced in C# 7.0. They have access to the variables of the surrounding method and therefore don't require the parameters in this case.
void myButton_Click(object sender, RoutedEventArgs e)
{
string[] allowedObjects = new string[...];
string[] notallowedObjects = new string[...];
storeParametersInArrays();
// Use the result
string firstAllowed = allowedObjects[0];
// Nested local function
void storeParametersInArrays()
{
// You can access allowedObjects, notallowedObjects and checkedListObjects here.
// Fill the arrays.
}
}
I have the following code:
private void AddMissingValue(ref string[] someArray) {
string mightbemissing="Another Value";
if (!someArray.Contains(mightbemissing)) {
var lst=someArray.ToList();
lst.Add(mightbemissing);
someArray=lst.ToArray();
}
}
While this works (Add an item to an array if missing), I wonder if this can be done in a smarter way? I don't like converting the array twice and writing so many lines for such a simple task.
Is there a better way? Maybe using LinQ?
General idea is right - array is a fixed-sized collection and you cannot add an item to it without recreating an array.
Your method can be written in a slightly more elegant way using LINQ .Concat method without creating a List:
private void AddMissingValue(ref string[] someArray)
{
string mightbemissing = "Another Value";
if (!someArray.Contains(mightbemissing))
{
someArray = someArray.Concat(new[] { mightbemissing }).ToArray();
}
}
This implementation takes N * 2 operations which is better than your N * 3, but it is still enumerating it multiple times and is quadratic for adding N items to your array.
If you are going to perform this operation too often, then changing your code to use dynamic-size collections (f.i., List) would be a more effective way.
Even if you decide to continue using arrays, it probably (imo) will look better if you return modified array instead of using ref:
private string[] AddMissingValue(string[] someArray)
{
string mightbemissing = "Another Value";
return someArray.Contains(mightbemissing)
? someArray
: someArray.Concat(new[] { mightbemissing }).ToArray();
}
// Example usage:
string[] yourInputArray = ...;
yourInputArray = AddMissingValue(yourInputArray);
LINQ-style and the most performant
Another implementation which comes to my mind and is the best (O(N)) in terms of performance (not against dynamic-size collections, but against previous solutions) and is LINQ-styled:
public static class CollectionExtensions
{
public static IEnumerable<T> AddIfNotExists<T>(this IEnumerable<T> enumerable, T value)
{
bool itemExists = false;
foreach (var item in enumerable)
{
if (!itemExists && value.Equals(item))
itemExists = true;
yield return item;
}
if (!itemExists)
yield return value;
}
}
// Example usage:
string[] arr = ...;
arr = arr.AddIfNotExists("Another Value").ToArray();
This implementation with yield is used to prevent multiple enumeration.
If you need to add multiple items, then it can even be rewritten this way, and it seems to still be linear:
public static IEnumerable<T> AddIfNotExists<T>(this IEnumerable<T> enumerable, params T[] value)
{
HashSet<T> notExistentItems = new HashSet<T>(value);
foreach (var item in enumerable)
{
if (notExistentItems.Contains(item))
notExistentItems.Remove(item);
yield return item;
}
foreach (var notExistentItem in notExistentItems)
yield return notExistentItem;
}
// Usage example:
int[] arr = new[] { 1, 2, 3 };
arr = arr.AddIfNotExists(2, 3, 4, 5).ToArray(); // 1, 2, 3, 4, 5
You have to resize the array, see
https://msdn.microsoft.com/en-us/library/bb348051(v=vs.110).aspx
for details. Implementation:
// static: it seems that you don't want "this" in the method
private static void AddMissingValue(ref string[] someArray) {
string mightbemissing = "Another Value";
if (!someArray.Contains(mightbemissing)) {
Array.Resize(ref someArray, someArray.Length + 1);
someArray[someArray.Length - 1] = mightbemissing;
}
}
In you current implementation, you copy all the items twice which can be unwanted if the array is large
...
var lst=someArray.ToList(); // first: all data copied from array to list
lst.Add(mightbemissing);
someArray=lst.ToArray(); // second: all data copied from list to array
A better design, however, is to switch from fixed size array string[] to, say, List<string>:
List<string> someList = ...
if (!someList.Contains(mightbemissing))
someList.Add(mightbemissing); // <- just Add
if all the values should be not null and unique you can do further improvement:
HashSet<string> someHash = ...
someHash.Add(mightbemissing);
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
how to inset a new array to my jagged array
i have a problem, where i dont know how i can make a string array variable in array length.
i have this code now below:
string[] p = new string[10];
int num = 0;
foreach (Product products in GetAllProducts())
{
//do something
p[num]= "some variable result"
num++
}
The problem is, that i dont know how many of "p" i will get, although i know it atleast will be less than 10.
but if i put it on 0, i will get an error when i start it, because it doesn't know the "p[num]"
So i am looking for some way to make "p" have a variable length.
anyone could help me out a bit? thanx
============Solved==========
List<string> p = new List<string>();
int num = 0;
foreach (Product products in GetAllProducts())
{
string s= null;
//do something ( create s out of multiple parts += s etc.)
p.add(s)
num++
}
thanx to solution poster
Use an List<string> instead of an array, if you do not know the number of items you will need to add.
Your array length cannot be modified after it has been instantiated. Use ArrayList or Generic Lists.
var p = new new List<string>(10);
foreach (Product products in GetAllProducts())
{
//do something
p.Add("some variable result");
}
What does GetAllProducts() return? Does it have a count or a length?! You should call that first, save it in a variable, get the count/length and then declare your array!
There's two solution.
If you want to keep using array :
int num = 0;
var list = GetAllProducts();
string[] p = new string[list.Length]; // Or list.Count if this is a collection
foreach (Product products in list)
{
//do something
p[num] = "some variable result";
num++;
}
Otherwise you should use a List like this :
List<string> p = new List<string>();
foreach (Product products in GetAllProducts())
{
//do something
p.Add("some variable result");
}
Use Array.Resize() method, which allows to resize it (by n number of indexes).
In my exmaple I will reize by 1 on each step of the way:
string[] array = new string[3]; //create array
for (int i = 0; i < 5; i++)
{
if (array.Length-1 < i) //checking for the available length
{
Array.Resize(ref array, array.Length + 1); //when to small, create a new index
}
array[i] = i.ToString(); //add an item to array[index] - of i
}
Because your code is using a foreach on the result from GetAllProducts, then GetAllProducts must be returning a IEnumerable collection. Probably the best solution would be to simply assign the result of GetAllProducts to such a collection. For example, perhaps it already returns a list of strings? So you can do:
List<string> strings = GetAllProducts();
There is no need to have a foreach loop to create an array when you already have a collection anyway being returned from GetAllProducts.
Or simply:
var strings = GetAllProducts();
to let the compiler work out the type of strings.
Most things you can do with an array you can also do with a List, and some more (such as adding items to the end of the List).
Perhaps you can post the signature of GetAllProducts (especially its return type) so we can better advise you?
I see many gave you the right answer which is the use of Lists. If you still need an array in the end, you can easily convert your list into an Array like this :
string[] tempArray = myList.ToArray();
Consider i have ArrayLists like these,
1){int[],int,int[]}
2){int[],int[],int}
And i have a count, 'n'. If n is 3 then my arrayList should be,
1){int[],int[],int[],int,int[],int[],int[]}
2){int[],int[],int[],int[],int[],int[],int}
i.e The new ArrayList should contain 'n' times the Array int[].
For one thing, do you really have to use an ArrayList? The fact that you're holding different types of data in one collection suggests there's probably a better way of solving your problem. Anyway, you could do something like this:
public static ArrayList DuplicateIntArrays(ArrayList input, int copies)
{
ArrayList ret = new ArrayList();
foreach (object element in input)
{
if (element is int[])
{
for (int i=0; i < copies; i++)
{
ret.Add(element);
}
}
else
{
ret.Add(element);
}
}
return ret;
}