Having two param lists with same size - c#

The method PrintTimes(string a, int b) prints the string a, b times (i.e. PrintTimes("test",3) will print testtesttest).
I want to create a method, which will get a params array of strings and a params array of integers. So the call function will ook like this
PrintTimes("A","B","C","D",2,1,3,2);
Or
PrintTimes("A",2,"B",1,"C",3,"D",2)
Both of which will print AABCCCDD
Since there can be only one params parameter in a method, this is impossible. So is there a way to do this?
I know I can create a Class with a string and an int variable, and create a params array for the class. But I'd rather not, since it would involve constructing a new Class for each set

Why not using a class
public class PrintParameter
{
public int Count {get;set;}
public string Content{get;set;}
}
Then
public void PrintTimes(List<PrintParameter> inputs)
{
//for each input print the "Content", "Count" times
}
Or
public void PrintTimes(params PrintParameter[] inputs)
{
//for each input print the "Content", "Count" times
}
If you don't want to define a class you may try something like List<KeyValuePair<string,int>> or other alternatives such as List<Tuple<string,int>> and etc. However the preferred way of doing is to use a class with meaningful properties.

How about just dropping the params keyword and taking arrays instead? That is, make the signature PrintTimes(string[], int[]). PrintTimes(new[]{"A","B","C","D"}, new[]{2,1,3,2}); isn't that much more to write.

There are several ways you can go about solving this problem. While you can only have one params, you can just make both your parameters arrays:
PrintTimes(string[] strings, int[] printCounts)
{
// Assert strings.Length == printCounts.Length
for (int i = 0; i < strings.Length; i++)
{
for (int j = 0; j < printCounts[i]; j++)
{
// Print strings[i]
}
}
}
Then it can be called like this:
int[] numbers = new int[3] {1, 2, 3};
string[] names = new string[3] {"Matt", "Joanne", "Robert"};
PrintTimes(names, numbers);

Following up on Hossein's suggestion, why not something as simple as:
void PrintTimes(List<String> strings, List<Int> count)
(or do it as an array as the comments said) Then inside PrintTimes require the inputs to be the same length or some logical fail when they don't.

Related

How do I use if/else in a generic function? C#

First I'd like to say that im pretty new in regards to coding, so don't kill me if the code looks horrible.
Alright, so the problem is that im trying to make a generic function which purpose is to take two sorted arrays and merge them into a new sorted array.
The problem im facing is trying to use if's in the function, and it doesn't let me use the < operand.
public object[] mergeTwoSorted<Tone, Ttwo>(Tone[] array, Ttwo[] array2)
{
object[] mergedArray = new object[array.Length + array2.Length];
for (int i = 0; i < mergedArray.Length; i++)
{
if (array is ValueType && array2 is ValueType)
{
if (array[i] > array2[i])
}
}
}
Any idea on how to tackle this problem?
First I'd like to say that im pretty new in regards to coding, so don't kill me if the code looks horrible.
It looks pretty reasonable so far. It looks like what you're trying to do is to take two sorted arrays of two different types, but there is an ordering relationship between the two types. You're then merging the two arrays into an array of objects, such that the objects from the two arrays are still in the same order, but they are interleaved with each other to match the inter-type ordering relation, yes?
That is an unusual thing to do, but it is possible.
If that is not what you are doing, then you need to stop and re-design the code. In particular, if your intention is to take two arrays of the same type, then you must have one type parameter, not two, and you must make an array of T as the output, not object.
The problem is that there is in general no way to express "I have an ordering relationship between these two types" in C#. You'll have to provide a function that does that. Traditionally we provide a function that takes the two types and returns an integer: -1 if the first is the smaller, 1 if the second is the smaller, and 0 if they are equal.
If we have that then your method becomes:
public static object[] MergeTwoSorted<TOne, TTwo> (
TOne[] items1,
TTwo[] items2,
Func<TOne, TTwo, int> comparer)
{
Note that we are using standard C# conventions here. Methods begin with a capital, type parameters are TSomething, and so on. A Func<A, B, C> is a function that takes an A, a B, and returns a C. Methods that do not manipulate an instance of their class are static.
Note that there is no need to re-state in the name of a thing what its type is. Say what the thing is logically, not how it is stored:
object[] merged = new object[items1.Length + items2.Length];
Now your loop needs some work:
for (int i = 0; i < mergedArray.Length; i++)
{
if (array is ValueType && array2 is ValueType)
{
if (array[i] > array2[i])
Arrays are never value types. I think you do not understand the difference between values and references, and that is really important to understand, so do some research on that.
Also, you have a counter i which counts the big merged array, but you use that as an index into the small arrays. That is very wrong; do you see why?
Think about it this way: you are going to count through both arrays at the same time filling in the merged array. So that would be:
int current1 = 0;
int current2 = 0;
while (current1 + current2 < merged.Length)
{
if (comparer(items1[current1], items2[current2]) < 0)
{
// items1[current1] is the smaller
merged[current1+current2] = items1[current1];
current1 += 1;
}
else
{
There is a bug in the code above; can you find it? Hint: indices for all array accesses must be >= 0 and < Length of the array. Is there a way in the code I've written so far that this gets violated?
Can you fix the bug and finish it off?
Can you now make a call site that takes an array of strings, an array of numbers, and an ordering relationship between strings and numbers, and merges the arrays?
public static object[] mergeTwoSorted<Tone, Ttwo>(Tone[] array, Ttwo[] array2)
where Tone : IComparable<Ttwo>
{
var mergedArray = new object[array.Length + array2.Length];
for (int i = 0; i < mergedArray.Length; i++)
{
if (array is ValueType && array2 is ValueType)
{
if (array[i].CompareTo( array2[i] )>0)
}
}
return mergedArray;
}
If you want to use specific operations on Generics, you have to limit them with a where clause accordingly. As when working with Fractural Numebrs, you need a common denominator.
Something like a "IMergable" interface that you have to write yourself.
public IMergeable[] mergeTwoSorted<Tone, Ttwo> (Tone[] array, Ttwo[] array2)
where Tone : IMergeable, Ttwo : IMergeable
{
IMergeable[] mergedArray = new IMergeable[array.Length + array2.Length];
for (int i = 0; i < mergedArray.Length; i++)
{
if (array is ValueType && array2 is ValueType)
{
if (array[i] > array2[i])
}
}
}
Alternatively, you could jsut use one type:
public Tone[] mergeTwoSorted<Tone> (Tone[] array, Tone[] array2)
{
IMergeable[] mergedArray = new IMergeable[array.Length + array2.Length];
for (int i = 0; i < mergedArray.Length; i++)
{
if (array is ValueType && array2 is ValueType)
{
if (array[i] > array2[i])
}
}
}

A two-dimensional ArrayList returns System.String[]

I have trouble with the value that arraylist returns.
I created a two-dimensional Arraylist that includes string arrays, when I try to get actual value of string arrays, I get System.String[] as output
instead of actual value of the arrays.
Why do I get System.String() as outuput?
Here is my code :
static void Main(string[] args)
{
string[] employee_1 = { "Employee1" };
string[] employee_2 = { "Employee2" };
ArrayList main_array = new ArrayList();
main_array.Add(employee_1);
main_array.Add(employee_2);
for (int i= 0; i < 2; i++)
{
Console.WriteLine(main_array[i]);
}
Console.ReadKey();
}
That is because when retrieving the items from an ArrayList what you are getting is a reference to an object instead of the actual type. Thus when printing it is calls the ToString of object (which prints the type's name) and not the string you want. In addition when printing a collection (like you are doing in your WriteLine command) you need to specify how to so do because it's default implementation is also as object's. You can use string.Join to print all items in the nested array.
To correct this first cast to string[] ( as string[]) and then print, or better still is to work with the list object instead: List<string[]>. To read more see:
ArrayList vs List<> in C#
What is the difference between an Array, ArrayList and a List?
So:
var mainCollection = new List<string[]> { new string[] { "Employee1" },
new string[] { "Employee2" }};
for (int i = 0; i < mainCollection.Count; i++)
{
Console.WriteLine(string.Join(", ", mainCollection[i]));
}
Console.ReadKey();
As a side note do not loop to 2 but instead by the number of items in the collection. See: What is a magic number, and why is it bad?
This is the default behaviour of ToString() function for an array.
To print the employees names, you need to iterate the array:
for (int i= 0; i < 2; i++)
{
foreach(string employee in main_array[i]) {
Console.WriteLine(employee);
}
}
The problem is here, ArrayList always take input as an object. So, when you add string array at an ArrayList, it take an object instead of string array.
So, you should convert this object to string array and print it.
like below:
for (int i = 0; i < 2; i++)
{
Console.WriteLine(string.Join(", ", main_array[i] as string[]));
}
or may use below(both are same):
for (int i = 0; i < 2; i++)
{
foreach (string employee in main_array[i] as string[])
{
Console.WriteLine(employee);
}
}
Because you have string[] type elements in outer ArrayList.
The best examples to enumerate are in answers above. If you realy need string content of string to be wtitten you should use
Console.WriteLine(((string[])main_array[i])[0]);
main_array is a two position ArrayList, each position contains a string[] this is, a string array.
If you use main_array[0], this is a reference to employee_1 which is a string array.
You should be able to reference the array strings by using main_array[0][0]
Try this:
foreach(var strArray in main_array)
{
// strArray is a string array
foreach(var stir in strArray)
{
// star is a string
Console.WriteLine(str);
}
}

Returning an Array Manipulates Original Value in C#

This is my first question on the site and I am sure I'll find my answer here.
For school, I was trying to do some basic C# coding for a challenge that was given to us.
Here is the problem:
Normally when I pass a value through a method I don't run into issues. Like so:
static void Main(string[] args)
{
// Declare Integer
int originalInt = 20;
// Call the Method
int multipliedInt = Multiplication(originalInt);
// Prompt
Console.WriteLine("Original: {0} Modified: {1}", originalInt, multipliedInt);
}
// Method
static public int Multiplication(int original)
{
// Quik Maffs
int modifiedValue = original * 2;
return modifiedValue;
}
The above example works just fine. The original value is 20 and the modified value is 40.
However, this changes when I attempt to do that with an array:
static void Main(string[] args)
{
// Declare Original Array
int[] originalArray = new int[] {1, 4, 6, 8, 12};
// Call Method
int[] multipliedArray = Multiplication(originalArray);
// Prompt
Console.WriteLine("Original: [{0}], Multiplied: [{1}]", String.Join(", ", originalArray), String.Join(", ", multipliedArray));
}
// Method
static public int[] Multiplication(int[] original)
{
// New Int
int[] modified = original;
// Loop
for (int i = 0; i < modified.Length; i++)
{
modified[i] *= 2;
}
return modified;
}
The code above returned the modified value twice. It seems like it modifies the original value as well.
Any idea why this is happening?
int is a value type. When you pass a value type to a method, you pass a copy of the value.
Arrays are reference types. When you pass a reference type to a method, you pass a copy of the reference... but both the copy and original still refer to the same object.
Now it seems you may have understood this much, because of this code:
(This is why I re-opened the question... the stock ref-vs-value answer wasn't gonna cut it here)
int[] modified = original;
However, the other thing that happens with reference types is assignments also only copy the reference. So modified and original in that snippet again refer to the same array object.
To fix this, you need to make an actual deep copy of the array. There are several ways to do this. I would tend to write the method this way:
static public IEnumerable<int> Multiplication(IEnumerable<int> original)
{
return original.Select(i => i * 2);
}
...and append a .ToArray() at the end of the method call if and only if I really need a full array (hint: very often it turns out you don't), like this:
int[] multipliedArray = Multiplication(originalArray).ToArray();
or like this:
var multipliedArray = Multiplication(originalArray);
But I understand there are a number of things here that aren't very familiar to a beginner. You might try something more like this:
static public int[] Multiplication(int[] original)
{
int[] modifed = new int[original.Length];
for (int i = 0; i < original.Length; i++)
{
modified[i] = original[i] * 2;
}
return modified;
}

How can I reference a 3D array from another class?

In the main program class I have:
static void Main()
{
string[,,] anArray = new string [3,3,3];
anArray[0,0,0] = "value1";
anArray[0,0,1] = "value2"; .... //filling the rest of the array.
}
How can I pass this array into another separate class "anotherClass" using a constructor with multiple arguments like:
class AnotherClass
{
private string[,,] anotherClassArray;
public string[,,] AnotherClassArray
{
get { return anotherClassArray;}
}
public AnotherClass (string[,,] fromAnArray)
{
anotherClassArray = new string [fromAnArray.Length];
}
}
I've seen examples with just a simple 1 dimensional array being passed from the Main program into another separate class and back again but when I tried following the same example for a multidimensional I get the error:
"Cannot implicitly convert type 'string[]' to 'string[,,*]'" when trying to initialize the new array.
If you want AnotherClass to have it's own separate, empty, instance of a 3D array, then you can do what Pikoh said. In this case, if you change the contents of the array, the original array created in Main is unaffected, and vice versa.
If you want AnotherClass to reference the same array as the one created in Main, and therefor have access to it's same, filled in contents, then simply set the AnotherClass.anotherClassArray reference to equal fromAnArray in the AnotherClass constructor like so:
public AnotherClass (string[,,] fromAnArray)
{
anotherClassArray = fromAnArray;
}
You can do it like this:
string[, ,] anotherClassArray = new string[anArray.GetLength(0),
anArray.GetLength(1),
anArray.GetLength(2)];
Update
As a experiment, if you want make this to generic for any unknown number of dimensions, you can use this method:
private Array CreateArrayWithSameDimensions(Array inArray)
{
int[] lengths = new int[inArray.Rank];
for (int i = 0; i < inArray.Rank; i++)
{
lengths[i] = inArray.GetLength(i);
}
Array myArray = Array.CreateInstance(typeof(string), lengths);
return myArray;
}
The problem with this approach is that accessing this array is not as simple as with known dimensions. This is an example of usage:
Array myArray = CreateArrayWithSameDimensions(anArray);
int[] indices = new int[anArray.Rank];
for (int i = 0; i < anArray.Rank; i++)
{
indices[i] = 0;
}
myArray.SetValue("test", indices);
This would set test in the lower bound index of that array. If the input array was a 3 dimensional array, in myArray[0,0,0] we would have test.

Is there any way to initialize several variables from one array? [duplicate]

This question already has answers here:
c# multi assignment
(7 answers)
Closed 8 years ago.
In some languages it is possible to initialize several variables at the same time from an array.
For example in PHP you can do something like this:
$array = array('a', 'b', 'c');
list($a, $b, $c) = $array;
Is it possible to do this in C# as well?
I want to apply this on a program where I read all lines from a file where I know every line is two words only (never more, never less).
I know I can create the function myself (and sending in variables by reference with outkeyword) but I would like to know if any built in functionality exists for it.
I would like to know this mostly for the reason that if it is possible the code might be more readable for other developers.
In C#,
string[] arr1 = new string[] { "one", "two", "three" };
string s1 = arr1[0];
string s2 = arr1[1];
string s3 = arr1[2];
If readability is the issue and if I understand you correctly - I don't know of an in-built way. But you can create a function for that.
void Doit(out string one, out string two, string[] input)
{
one = input[0];
two = input[1];
}
And use it thus:
string[] s = new string[] { "First", "Second" };
string a, b;
Doit(out a, out b, s);
I just realized that you don't need my answer. (I had initially understood "I know I can create the function myself..." differently.) Perhaps, though, it can help someone else.
char[] array = new char[] {'a','b','c'};
As far as I know there is no buit-in way to do that.
Maybe a good way to implement that functionality is by using extension methods in order to improve readability.
Simply write the needed code in a extension method that can be attached to the type you want to initialize like a list in your example above and take an array as input to that function:
public static class Extensions {
public static void initFromArray<T> (this List<T> list, T[] array) {
for (int i = 0; i < array.Length; i++) {
list[i] = array[i];
}
}
}
Then you can use this method for example like in the following:
int[] array = new int [] { 1, 4, 6, 2, 5 };
List<int> list = new List<int>();
for (int i = 0; i < 4; i++) list.Add(0);
list.initFromArray<T>(array);

Categories