Related
I have a list of tuples that I want to modify.
var myList = new List<(int head, int[] tail)> {
(0, new[] { 1, 2, 3 }),
(7, new[] { 8, 9 } ), };
var myArray = new (int head, int[] tail)[] {
(0, new[] { 1, 2, 3 }),
(7, new[] { 8, 9 } ), };
// ...
// ref var firstElement = ref myList[0];
ref var firstElement = ref myArray[0];
firstElement.head = 99;
This works perfectly for arrays, but not for lists.
I understand that this is because the indexer doesn't do a ref return; but is there some other way that lists can return their elements by reference, so that I can modify the returned tuple?
This will cause a compiler error "A property or indexer may not be passed as an out or ref parameter":
ref var firstElementList = ref myList[0];
As I understand it happens because compiler is aware of array and doesn't call indexer for it. While for list it calls indexer and for indexer you cannot use ref(without ref in indexer signature), according to MSDN.
For this
var firstElement = myArray[0];
firstElement.head = 99;
Ildasm shows this
ldelem valuetype [System.Runtime]System.ValueTuple`2<int32,int32[]>
MSDN
I.e. arrays are supported on IL level.
While for list it calls indexer.
callvirt instance !0 class [System.Collections]System.Collections.Generic.List`1<valuetype [System.Runtime]System.ValueTuple`2<int32,int32[]>>::get_Item(int32)
And for indexer it works if you put ref to the signature.
E.g.(it is only for demonstration purposes; yep, there should be array instead of single variable, etc, but just to get it compilable)
class Program
{
static void Main(string[] args)
{
var myList = new MyList<(int head, int[] tail)> {
(0, new[] { 1, 2, 3 }),
(7, new[] { 8, 9 } ), };
ref var firstElement = ref myList[0];
firstElement.head = 99;
Console.WriteLine("Hello World!");
}
}
public class MyList<T> : IEnumerable
{
private T value;
public ref T this[int index]
{
get
{
return ref value;
}
}
public void Add(T i)
{
value = i;
}
public IEnumerator GetEnumerator() => throw new NotImplementedException();
}
P.S. But when you start implementing your own list implementation(as array list) you will probable notice that it is not worth having ref indexer - imagine you resized the array - created the new one and copied all the data; it means someone might hold non actual reference.
P.P.S Going further, say we creating linked list - nothing wrong will happen on just resize, but imagine we removed an element someone is holding a reference to - it is not possible to understand it doesn't belong to the list any longer.
So, yes, I think they intentionally made List indexer non ref since it doesn't seem to be a good idea having ref return for something that can change.
You can do this using WeakReference and changing ValueTuple to class:
List<MyClass> myList = new List<MyClass> {
new MyClass { Head = 0, Tail = new[] { 1, 2, 3 } },
new MyClass { Head = 7, Tail = new[] { 8, 9 } } };
var firstElement = new WeakReference(myList[0]);
MyClass reference = firstElement.Target as MyClass;
reference.Head = 99;
firstElement.Target = new MyClass { Head = 99, Tail = reference.Tail};
Console.WriteLine(myList[0].Head);
You can try this code here.
I tried like below
public int[] GetCompletedCalls()
{
int[] minMax = int[2];
minMax[0] = countCompleted;
minMax[1] = countPendings;
return minMax;
}
But at declaring an array variable throwing an error: Invalid
expression term 'int'
you need to use the new keyword:
int[] minMax = new int[2];
There are multiple ways to achieve this. The easiest one needs only a single correction:
int[] minMax = int[2];
should be
int[] minMax = new int[2];
Another opportunity is to do this:
return new [] { countCompleted, countPendings};
or also this:
public void GetCompletedCalls(out int completed, out int pending)
{
completed = countCompleted;
pending = countPendings;
}
or also this which uses a Tuple instead (requires C#7):
public (int, int) GetCompletedCalls()
{
return (countCompleted, countPendings);
}
I have a constructor which uses a List parameter. Inside that list I have three items which are 3 integer arrays.
public HistogramLogic(List<Tuple<int[], int[], int[]>> separateRGB)
Now I want to initialize three new integer arrays with the arrays inside that list. But when I try this code, the index of my new arrays stay 0.
for (int i = 0; i < histogramXValues.Length; i++)
{
rArray = separateRGB.Select(obj => obj.Item1[i]).ToArray();
gArray = separateRGB.Select(obj => obj.Item2[i]).ToArray();
bArray = separateRGB.Select(obj => obj.Item3[i]).ToArray();
}
Anyone got any suggestions on how to fix this?
Bear in mind, if you have a list of N tuples, you start with 3 x N arrays. Sounds like you want them combined into 3 arrays, each containing all of the elements throughout the list. Which you can do with SelectMany.
rArray = separateRGB.SelectMany(obj => obj.Item1).ToArray();
gArray = separateRGB.SelectMany(obj => obj.Item2).ToArray();
bArray = separateRGB.SelectMany(obj => obj.Item3).ToArray();
Full example:
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
static public void HistogramLogic(List<Tuple<int[], int[], int[]>> separateRGB)
{
var rArray = separateRGB.SelectMany(obj => obj.Item1).ToArray();
var gArray = separateRGB.SelectMany(obj => obj.Item2).ToArray();
var bArray = separateRGB.SelectMany(obj => obj.Item3).ToArray();
Console.WriteLine("rArray = {{{0}}}", string.Join(",", rArray));
Console.WriteLine("gArray = {{{0}}}", string.Join(",", gArray));
Console.WriteLine("bArray = {{{0}}}", string.Join(",", bArray));
}
public static void Main()
{
var mockData = new List<Tuple<int[], int[], int[]>>
{
Tuple.Create(new[] {11,12,13}, new[] {14,15,16}, new[] {17,18,19}),
Tuple.Create(new[] {21,22,23}, new[] {24,25,26}, new[] {27,28,29}),
Tuple.Create(new[] {31,32,33}, new[] {34,35,36}, new[] {37,38,39})
};
HistogramLogic(mockData);
}
}
Output:
rArray = {11,12,13,21,22,23,31,32,33}
gArray = {14,15,16,24,25,26,34,35,36}
bArray = {17,18,19,27,28,29,37,38,39}
Click here for code on DotNetFiddle
You can just get the item from touple
rArray = separateRGB.Select(obj => obj.Item1);
Like they sad in comments you did reassign local member in each loop.
You could use something like this.
public HistogramLogic(List<Tuple<int[], int[], int[]>> separateRGB)
{
List<int> rList = new List<int>();
List<int> gList = new List<int>();
List<int> bList = new List<int>();
separateRGB.ForEach((Tuple<int[], int[], int[]> tpl) =>
{
rList.AddRange(tpl.Item1);
gList.AddRange(tpl.Item1);
bList.AddRange(tpl.Item1);
});
rArray = rList.ToArray();
gArray = gList.ToArray();
bArray = bList.ToArray();
}
If you wish to not use temp List object you should know final count of elements in tuple, create local array member to desired size. and fill it. List are more suitable for adding and expanding elements. Maybe you could use one Linq Statement but if I understand goal is to get one int[] array per color. If you take
separateRGB.AsQueryable().Select(m => m.Item1).ToArray();
as a result you get int[][] result instead of simple int array;
there some method equal list() of php in C#?
usage list() in PHP:
$array = array('foo','baa');
list($foo, $baa) = $array;
echo $foo; //foo
echo $baa; //baa
equivalent in javascript:
var arr = ['foo','baa'];
var foo;
var baa;
[foo, baa] = arr;
Thanks in advance!
There is no direct language equivalent in C#. While collection initializers can be used to construct the array, there is no way to extract elements directly.
This requires explicitly setting variables, ie:
var theArray = GetArrayFromSomewhere();
var foo = theArray[0];
var bar = theArray[1];
This is more similar to the original intention, though some might not like all the ceremony :
string a = null, b = null, c = null;
new ValList(v => a = v,
v => b = v,
v => c = v).SetFrom(new string[] { "foo", "bar" });
//here a is "foo", b will be "bar", and c is still null
And the simple helper class:
class ValList
{
private Action<string>[] _setters;
public ValList(params Action<string>[] refs)
{
_setters = refs;
}
internal void SetFrom(string[] values)
{
for (int i = 0; i < values.Length && i < _setters.Length; i++)
_setters[i](values[i]);
}
}
One way to do the original php (I know nothing about PHP) task in C# would be
List<string> name_list = new List<string>{"transmogrify","untransmogrify"};
name_list.ForEach(x => Debug.WriteLine(x));
Which leads to the more general observation, that C# allows you to do a lot while leaving the variables in the array or list. LINQ in particular makes doing many things quite simple. So if you are looking for a way to replicate some PHP code in C# I would think in those terms. Just one parting example, if you had an array of ints you wanted to sum you could do this
int[] some_ints = {1, 2, 3, 4};
int sum += some_ints.Sum();
As Reed said ,
There is no direct language equivalent in C#.
But you can create it like below ↓
class Program
{
static void Main(string[] args)
{
string[] tmp = new string[] { "foo", "baa" };
string foo, baa;
tmp.Go(out foo, out baa);
Console.WriteLine(foo);
Console.WriteLine(baa);
Console.ReadKey();
}
}
public static class PHPList
{
public static void Go(this string[] soruce, out string p1, out string p2)
{
p1 = soruce[0] + "";
p2 = soruce[1] + "";
}
}
Just piggy-backing #Yoni's answer into an extension method. This was a cute and silly exercise; however, as has been pointed out in comments and answers, some language features simply do not port from one language to another.
In PHP, list($a, $b) = $c constitutes an assignment, and since no variable declarations are required (the list() is the declaration) it can provide terse and clean assignment syntax.
In C# however, since variable declarations are required prior to usage, you're better off simply assigning the value off the list at that time, as the following example will show.
Speaking of, incoming example:
public static void Into<TSource>(this IEnumerable<TSource> source,
params Action<TSource>[] actions)
{
if (ReferenceEquals(source, null)) {
throw new ArgumentNullException("source");
}
if (ReferenceEquals(actions, null)) {
throw new ArgumentNullException("actions");
}
foreach (var assignment in actions.Zip(source, (action, item) => new {
Action = action,
Item = item,
})) {
assignment.Action.Invoke(assignment.Item);
}
}
So you can simply collection.Into(o => a = o, o => ...); for example:
var numbers = new[] { 1, 2, 3, 4, 5 };
int a = 0, b = 0, c = 0, d = 0;
int e = 0, f = 0, g = 0, h = 0, i = 0, j = 0;
numbers.Into(o => a = o,
o => b = o,
o => c = o,
o => d = o);
numbers.Into(o => e = o,
o => f = o,
o => g = o,
o => h = o,
o => i = o,
o => j = o);
This will yield:
Console.WriteLine(a); // 1
Console.WriteLine(b); // 2
Console.WriteLine(c); // 3
Console.WriteLine(d); // 4
Console.WriteLine(e); // 1
Console.WriteLine(f); // 2
Console.WriteLine(g); // 3
Console.WriteLine(h); // 4
Console.WriteLine(i); // 5
Console.WriteLine(j); // 0
Perhaps some Expression<> magic can shorten it to:
numbers.Into(o => a,
o => b,
... )
What are all the array initialization syntaxes that are possible with C#?
These are the current declaration and initialization methods for a simple array.
string[] array = new string[2]; // creates array of length 2, default values
string[] array = new string[] { "A", "B" }; // creates populated array of length 2
string[] array = { "A" , "B" }; // creates populated array of length 2
string[] array = new[] { "A", "B" }; // created populated array of length 2
Note that other techniques of obtaining arrays exist, such as the Linq ToArray() extensions on IEnumerable<T>.
Also note that in the declarations above, the first two could replace the string[] on the left with var (C# 3+), as the information on the right is enough to infer the proper type. The third line must be written as displayed, as array initialization syntax alone is not enough to satisfy the compiler's demands. The fourth could also use inference. So if you're into the whole brevity thing, the above could be written as
var array = new string[2]; // creates array of length 2, default values
var array = new string[] { "A", "B" }; // creates populated array of length 2
string[] array = { "A" , "B" }; // creates populated array of length 2
var array = new[] { "A", "B" }; // created populated array of length 2
The array creation syntaxes in C# that are expressions are:
new int[3]
new int[3] { 10, 20, 30 }
new int[] { 10, 20, 30 }
new[] { 10, 20, 30 }
In the first one, the size may be any non-negative integral value and the array elements are initialized to the default values.
In the second one, the size must be a constant and the number of elements given must match. There must be an implicit conversion from the given elements to the given array element type.
In the third one, the elements must be implicitly convertible to the element type, and the size is determined from the number of elements given.
In the fourth one the type of the array element is inferred by computing the best type, if there is one, of all the given elements that have types. All the elements must be implicitly convertible to that type. The size is determined from the number of elements given. This syntax was introduced in C# 3.0.
There is also a syntax which may only be used in a declaration:
int[] x = { 10, 20, 30 };
The elements must be implicitly convertible to the element type. The size is determined from the number of elements given.
there isn't an all-in-one guide
I refer you to C# 4.0 specification, section 7.6.10.4 "Array Creation Expressions".
Non-empty arrays
var data0 = new int[3]
var data1 = new int[3] { 1, 2, 3 }
var data2 = new int[] { 1, 2, 3 }
var data3 = new[] { 1, 2, 3 }
var data4 = { 1, 2, 3 } is not compilable. Use int[] data5 = { 1, 2, 3 } instead.
Empty arrays
var data6 = new int[0]
var data7 = new int[] { }
var data8 = new [] { } and int[] data9 = new [] { } are not compilable.
var data10 = { } is not compilable. Use int[] data11 = { } instead.
As an argument of a method
Only expressions that can be assigned with the var keyword can be passed as arguments.
Foo(new int[2])
Foo(new int[2] { 1, 2 })
Foo(new int[] { 1, 2 })
Foo(new[] { 1, 2 })
Foo({ 1, 2 }) is not compilable
Foo(new int[0])
Foo(new int[] { })
Foo({}) is not compilable
Enumerable.Repeat(String.Empty, count).ToArray()
Will create array of empty strings repeated 'count' times. In case you want to initialize array with same yet special default element value. Careful with reference types, all elements will refer same object.
In case you want to initialize a fixed array of pre-initialized equal (non-null or other than default) elements, use this:
var array = Enumerable.Repeat(string.Empty, 37).ToArray();
Also please take part in this discussion.
var contacts = new[]
{
new
{
Name = " Eugene Zabokritski",
PhoneNumbers = new[] { "206-555-0108", "425-555-0001" }
},
new
{
Name = " Hanying Feng",
PhoneNumbers = new[] { "650-555-0199" }
}
};
Example to create an array of a custom class
Below is the class definition.
public class DummyUser
{
public string email { get; set; }
public string language { get; set; }
}
This is how you can initialize the array:
private DummyUser[] arrDummyUser = new DummyUser[]
{
new DummyUser{
email = "abc.xyz#email.com",
language = "English"
},
new DummyUser{
email = "def#email.com",
language = "Spanish"
}
};
Just a note
The following arrays:
string[] array = new string[2];
string[] array2 = new string[] { "A", "B" };
string[] array3 = { "A" , "B" };
string[] array4 = new[] { "A", "B" };
Will be compiled to:
string[] array = new string[2];
string[] array2 = new string[] { "A", "B" };
string[] array3 = new string[] { "A", "B" };
string[] array4 = new string[] { "A", "B" };
Repeat without LINQ:
float[] floats = System.Array.ConvertAll(new float[16], v => 1.0f);
int[] array = new int[4];
array[0] = 10;
array[1] = 20;
array[2] = 30;
or
string[] week = new string[] {"Sunday","Monday","Tuesday"};
or
string[] array = { "Sunday" , "Monday" };
and in multi dimensional array
Dim i, j As Integer
Dim strArr(1, 2) As String
strArr(0, 0) = "First (0,0)"
strArr(0, 1) = "Second (0,1)"
strArr(1, 0) = "Third (1,0)"
strArr(1, 1) = "Fourth (1,1)"
For Class initialization:
var page1 = new Class1();
var page2 = new Class2();
var pages = new UIViewController[] { page1, page2 };
Another way of creating and initializing an array of objects. This is similar to the example which #Amol has posted above, except this one uses constructors. A dash of polymorphism sprinkled in, I couldn't resist.
IUser[] userArray = new IUser[]
{
new DummyUser("abc#cde.edu", "Gibberish"),
new SmartyUser("pga#lna.it", "Italian", "Engineer")
};
Classes for context:
interface IUser
{
string EMail { get; } // immutable, so get only an no set
string Language { get; }
}
public class DummyUser : IUser
{
public DummyUser(string email, string language)
{
m_email = email;
m_language = language;
}
private string m_email;
public string EMail
{
get { return m_email; }
}
private string m_language;
public string Language
{
get { return m_language; }
}
}
public class SmartyUser : IUser
{
public SmartyUser(string email, string language, string occupation)
{
m_email = email;
m_language = language;
m_occupation = occupation;
}
private string m_email;
public string EMail
{
get { return m_email; }
}
private string m_language;
public string Language
{
get { return m_language; }
}
private string m_occupation;
}
For the class below:
public class Page
{
private string data;
public Page()
{
}
public Page(string data)
{
this.Data = data;
}
public string Data
{
get
{
return this.data;
}
set
{
this.data = value;
}
}
}
you can initialize the array of above object as below.
Pages = new Page[] { new Page("a string") };
Hope this helps.
hi just to add another way:
from this page :
https://learn.microsoft.com/it-it/dotnet/api/system.linq.enumerable.range?view=netcore-3.1
you can use this form If you want to Generates a sequence of integral numbers within a specified range strat 0 to 9:
using System.Linq
.....
public int[] arrayName = Enumerable.Range(0, 9).ToArray();
You can also create dynamic arrays i.e. you can first ask the size of the array from the user before creating it.
Console.Write("Enter size of array");
int n = Convert.ToInt16(Console.ReadLine());
int[] dynamicSizedArray= new int[n]; // Here we have created an array of size n
Console.WriteLine("Input Elements");
for(int i=0;i<n;i++)
{
dynamicSizedArray[i] = Convert.ToInt32(Console.ReadLine());
}
Console.WriteLine("Elements of array are :");
foreach (int i in dynamicSizedArray)
{
Console.WriteLine(i);
}
Console.ReadKey();
Trivial solution with expressions. Note that with NewArrayInit you can create just one-dimensional array.
NewArrayExpression expr = Expression.NewArrayInit(typeof(int), new[] { Expression.Constant(2), Expression.Constant(3) });
int[] array = Expression.Lambda<Func<int[]>>(expr).Compile()(); // compile and call callback
To initialize an empty array, it should be Array.Empty<T>() in dotnet 5.0
For string
var items = Array.Empty<string>();
For number
var items = Array.Empty<int>();
Another way is by calling a static function (for a static object) or any function for instance objects. This can be used for member initialisation.
Now I've not tested all of this so I'll put what I've tested (static member and static function)
Class x {
private static Option[] options = GetOptionList();
private static Option[] GetOptionList() {
return (someSourceOfData).Select(dataitem => new Option()
{field=dataitem.value,field2=dataitem.othervalue});
}
}
What I'd love to know is if there is a way to bypass the function declaration. I know in this example it could be used directly, but assume the function is a little more complex and can't be reduced to a single expression.
I imagine something like the following (but it doesn't work)
Class x {
private static Option[] options = () => {
Lots of prep stuff here that means we can not just use the next line
return (someSourceOfData).Select(dataitem => new Option()
{field=dataitem.value,field2=dataitem.othervalue});
}
}
Basically a way of just declaring the function for the scope of filling the variable.
I'd love it if someone can show me how to do that.
For multi-dimensional array in C# declaration & assign values.
public class Program
{
static void Main()
{
char[][] charArr = new char[][] { new char[] { 'a', 'b' }, new char[] { 'c', 'd' } };
int[][] intArr = new int[][] { new int[] { 1, 2 }, new int[] { 3, 4 } };
}
}