(edit: Slight tidy of the code.)
Using foreach like this works fine.
var a = new List<Vector2>();
a.ForEach(delegate(Vector2 b) {
b.Normalize(); });
The following however causes "No overload for method 'ForEach' takes 1 arguments".
byte[,,] a = new byte[2, 10, 10];
a.ForEach(delegate(byte b) {
b = 1; });
I would recommend you just use a normal foreach loop to transform the data. You're using a method that exists only on the List<T> implementation, but not on arrays.
Using a method for foreach really gains you nothing, unless for some reason you were wanting to do data mutation in a method chain. In that case, you may as well write your own extension method for IEnumerable<T>. I would recommend against that, though.
Having a separate foreach loop makes it clear to the reader that data mutation is occurring. It also removes the overhead of calling a delegate for each iteration of the loop. It will also work regardless of the collection type as long as it is an IEnumerable (not entirely true, you can write your own enumerators and enumerables, but that's a different question).
If you're looking to just do data transformations (i.e. projections and the like) then use LINQ.
Also keep in mind that with the array, you're getting a copy of the byte not a reference. You'll be modifying just that byte not the original. Here's an example with the output:
int[] numbers = new int[] { 1, 2, 3, 4, 5 };
Array.ForEach(numbers, number => number += 1);
foreach(int number in numbers)
{
Console.WriteLine(number);
}
Which yields the output:
1
2
3
4
5
As you can see, the number += 1 in the lambda had no effect. In fact, if you tried this in a normal foreach loop, you would get a compiler error.
You're using two different ForEach'es.
Array.ForEach in the byte[,,] example (though you're using it incorrectly) and List.ForEach in the List<...> example.
You've used syntax of List.ForEach() method for the array, but Array.ForEach() syntax is:
public static void ForEach<T>(
T[] array,
Action<T> action
)
One important point that array should be one-dimensional in order to use it in Array.ForEach(). Considering this I would suggest using simple for loop
// first dimension
for (int index = 0; index < bytesArray.GetLength(0); index++)
// second dimension
for (int index = 0; index < bytesArray.GetLength(1); index++)
// third dimension
for (int index = 0; index < bytesArray.GetLength(2); index++)
I don't know of a ForEach method that takes multi-dimensional arrays.
If you want one, i think you will have to create it yourself.
Here is how to do it:
private static void ForEach<T>(T[, ,] a, Action<T> action)
{
foreach (var item in a)
{
action(item);
}
}
Sample program, using the new ForEach method:
static class Program
{
static void Main()
{
byte[, ,] a = new byte[2, 10, 10];
ForEach(a, delegate(byte b)
{
Console.WriteLine(b);
});
}
private static void ForEach<T>(T[, ,] a, Action<T> action)
{
foreach (var item in a)
{
action(item);
}
}
}
Also, the ForEach method in the Array version, is not an instance method, it is statis method. You call it like this:
Array.ForEach(array, delegate);
raw arrays have much less instance methods than generic collections because they are not templated. These methods, such as ForEach() or Sort() are usually implemented as static methods which are themselves templated.
In this case, Array.Foreach(a, action) will do the trick for the array.
Of course, the classical foreach(var b in a) would work for both List and Array since it only requires an enumerator.
However:
I'm not sure how you'd loop over a multidimensional array.
Your assignment (b=1) won't work. Because you receive a value, not a reference.
List has the first instance method. Arrays do not.
Related
Given an array of int numbers like:
int[] arr = new int[] { 0, 1, 2, 3, 4, 5 };
If we want to increment every number by 1, the best choice would be:
for(int i = 0; i < arr.Length; i++)
{
arr[i]++;
}
If we try to do it using foreach
foreach(int n in arr)
{
n++;
}
as expected, we meet the error:
Cannot assign to 'n' because it is a 'foreach iteration variable'
Why if we use this approach:
Array.ForEach(arr, (n) => {
n++;
});
which is equal to the foreach above, visual studio and compiler aren't going to tell us anything, the code is going to compile and just not producing any result in runtime, neither throw an exception?
foreach(int n in arr)
{
n++;
}
This is a language construct, the compiler knows exactly what a foreach-loop is supposed to do and what nis. It can therefore prevent you from changing the iteration variable n.
Array.ForEach(arr, (n) => {
n++;
});
This is a regular function call passing in a lambda. It is perfectly valid to modify local variables in a function (or lambda), so changing n is okay. While the compiler could warn you that the increment has no effect as it's never been used afterwards, it's valid code, and just because the function is called ForEach and actually does something similar to the foreach-loop doesn't change the fact that this is a regular function and a regular lambda.
As pointed out by #tkausl, n with ForEach is a local variable. Therefore:
static void Main()
{
int[] arr = new int[] { 0, 1, 2, 3, 4, 5 };
Console.WriteLine(string.Join(" ",arr));
Array.ForEach(arr, (n) => {
n++;
});
Console.WriteLine(string.Join(" ",arr));
}
will output:
0 1 2 3 4 5
0 1 2 3 4 5
Meaning you don't change the values of arr.
Array.ForEach is not identical to a foreach-loop. It´s an extension-method which will iterate a collection and performs an action on every of its elements.
Array.ForEach(arr, (n) => {
n++;
});
however won´t modify the actuzal collection, it will just re-assign a new value to n which has no relation to the underlying value in the array, because it´s a value-type which is **copied* to the anonymous method. So whatever you do with the param in your anonymous method isn´t reflected to the ForEach-method and thus has no effect in your array. This is why you can do this.
But even if you had an array of reference-types that would work, because you simply re-assign a new instance to the provided parameter, which again has no effect to the underlying array.
Take a look at this simplified example:
MyClass
{
void ForEach(Action<Item> a)
{
foreach(var e in myList)
Action(e);
}
}
In your case the action looks like this:
x => x++
which simply assigns a new value to x. As x however is passed by value, this won´t have any effect to the calling method and thus to myList.
Both are two different things.
First we need to be clear what we need. If the requirement is to mutate the existing values then you can use for loop as modifying the values while enumerating the collection shouldn't be done that' why you face error for the first foreach loop.
So one approach could be if mutating is the intention:
for(int i=0; i< arr.Length; i++)
{
arr[i] = arr[i] +1;
}
Secondly, If the intention is to get a new collection with the updated values then consider using linq Select method which will return a new collection of int.
var incrementedArray = arr.Select( x=> (x+1));
EDIT:
the key difference is in the first example we are modifying the values of colelction while enumerating it while in lambda syntax foreach a delegate is used which get input as local variable.
The foreach statement executes a statement or a block of statements for each element in an instance of the type that implements the System.Collections.IEnumerable or System.Collections.Generic.IEnumerable<T> interface. You cannot modify iterated value because you are using System.Collections.IEnumberable or System.COllections.Generic.IEnumberable<T> interfaces which support deferred execution.
If you want to modify value you can also use
foreach(ref int n in arr)
{
n++;
}
Updated
The Array.Foreach is a method that performs specified action on each element of the specified array. This function support immediate execution behavior and can be applied to only data that holds in memory. The Array.Foreach method take an array and used For loop to iterate through collection.
foreach and Array.Foreach both looks same but are different in their working.
C# allows creating and populating multidimensional arrays, here is a simple example:
public static void Main(String[] args)
{
var arr = (int[,])CreateArray(new [] {2, 3}, 8);
Console.WriteLine("Value: " + arr[0,0]);
}
// Creates a multidimensional array with the given dimensions, and assigns the
// given x to the first array element
public static Array CreateArray<T>(int[] dimLengths, T x)
{
var arr = Array.CreateInstance(typeof(T), dimLengths);
var indices = new int[dimLengths.Length];
for (var i = 0; i < indices.Length; i++)
indices[i] = 0;
arr.SetValue(x, indices); // Does boxing/unboxing
return arr;
}
This works well. However, for some reason there is no generic version of Array.SetValue(), so the code above does boxing/unboxing, which I'd like to avoid. I was wondering if I missed something or if this is an omission in the .NET API?
No, you are not missing anything: Arrays does not have an option that sets the value without boxing and unboxing.
You do have an alternative to this with LINQ, but it is probably going to be slower than boxing/unboxing for a single element, because compiling a dynamic lambda would "eat up" the potential benefits:
public static Array CreateArray<T>(int[] dimLengths, T x) {
var arr = Array.CreateInstance(typeof(T), dimLengths);
var p = Expression.Parameter(typeof(object), "arr");
var ind = new Expression[dimLengths.Length];
for (var i = 0; i < dimLengths.Length; i++) {
ind[i] = Expression.Constant(0);
}
var v = Expression.Variable(arr.GetType(), "cast");
var block = Expression.Block(
new[] {v}
, new Expression[] {
Expression.Assign(v, Expression.Convert(p, arr.GetType()))
, Expression.Assign(Expression.ArrayAccess(v, ind), Expression.Constant(x))
, Expression.Constant(null, typeof(object))
}
);
Expression.Lambda<Func<object, object>>(block, p).Compile()(arr);
return arr;
}
If you wanted to set all elements in a loop, you could modify the above to compile a dynamically created lambda with multiple nested loops. In this case, you could get an improvement on having to perform multiple boxing and unboxing in a series of nested loops.
for some reason there is no generic version of Array.SetValue()
While it is definitely possible to write a generic method similar to SetValue in the Array class, it may not be desirable. A generic method on a non-generic class would give a false promise of compile-time type safety, which cannot be guaranteed, because the compiler does not know the runtime type of the Array object.
I didn't find any generic ways either to set a value into an Array instance, so I guess the only workaround is to use the unsafe context to avoid boxing.
However, there can be no generic version, now when I think of it. See, when you define a generic method method<T>()..., you do define the parameter for the method: ...<T>(T[] a)... where you have to be specific about the dimensions count, which is one. To create a twodimensional parameter, you define it like this ...<T>(T[,] a)... and so on.
As you can see, by the current syntax of C#, you simple cannot create a generic method, which can accept any-dimensional array.
consider the following C# program:
using System;
using System.Linq;
using System.Collections.Generic;
public class Test
{
static IEnumerable<Action> Get()
{
for (int i = 0; i < 2; i++)
{
int capture = i;
yield return () => Console.WriteLine(capture.ToString());
}
}
public static void Main(string[] args)
{
foreach (var a in Get()) a();
foreach (var a in Get().ToList()) a();
}
}
When executed under Mono compiler (e.g. Mono 2.10.2.0 - paste into here), it writes the following output:
0
1
1
1
This seems totally unlogical to me. When directly iterating the yield function, the scope of the for-loop is "correctly" (to my understanding) used. But when I store the result in a list first, the scope is always the last action?!
Can I assume that this is a bug in the Mono compiler, or did I hit a mysterious corner case of C#'s lambda and yield-stuff?
BTW: When using Visual Studio compiler (and either MS.NET or mono to execute), the result is the expected 0 1 0 1
I'll give you the reason why it was 0 1 1 1:
foreach (var a in Get()) a();
Here you go into Get and it starts iterating:
i = 0 => return Console.WriteLine(i);
The yield returns with the function and executes the function, printing 0 to the screen, then returns to the Get() method and continues.
i = 1 => return Console.WriteLine(i);
The yield returns with the function and executes the function, printing 1 to the screen, then returns to the Get() method and continues (only to find that it has to stop).
But now, you're not iterating over each item when it happens, you're building a list and then iterating over that list.
foreach (var a in Get().ToList()) a();
What you are doing isn't like above, Get().ToList() returns a List or Array (not sure wich one). So now this happens:
i = 0 => return Console.WriteLine(i);
And in you Main() function, you get the following in memory:
var i = 0;
var list = new List
{
Console.WriteLine(i)
}
You go back into the Get() function:
i = 1 => return Console.WriteLine(i);
Which returns to your Main()
var i = 1;
var list = new List
{
Console.WriteLine(i),
Console.WriteLine(i)
}
And then does
foreach (var a in list) a();
Which will print out 1 1
It seems like it was ignoring that you made sure you encapsulated the value before returning the function.
#Armaron - The .ToList() extension returns List of type T as ToArray() returns T[] as the naming convention implies, but I think you are on the right track with your response.
This sounds like an issuse with the compiler. I agree with Servy that it is probably a bug, however, have you tried the following?
public class Test
{
private static int capture = 0;
static IEnumerable<Action> Get()
{
for (int i = 0; i < 2; i++)
{
capture++;
yield return () => Console.WriteLine(capture.ToString());
}
}
}
Additionally you may want to try the static approach, perhaps this will perform a more accurate conversion as your function is static.
List<T> list = Enumerable.ToList(Get());
When calling ToList() it seems as though it is not performing a single iteration for each value but rather:
return new List<T>(Get());
The second for each in your code does not make sense to me in implementation as to why it would ever be necessary or beneficial unless you require additional actions to be added/removed to the List object. The first makes perfect sense since all you are doing is iterating through the object and performing the associated action. My understanding is that an integer within the scope of the static IEnumerbale object is being calculated during conversion by performing the entire iteration and the action is preserving the int as a static int due to scope. Also, keep in mind that IEnumerable is merely an interface that is implemented by List which implements IList, and may contain logic for the conversion built in.
That being said I am interested to see/hear your findings as this is an interesting post. I will definitely upvote the question. Please ask questions if anything I said needs clarification or if something is false say so, although I am confident in my usage of the yield keyword of IEnumerable but this is a unique issue.
I ran into what was to me an unexpected result when testing a simple ForEach extension method.
ForEach method
public static void ForEach<T>(this IEnumerable<T> list, Action<T> action)
{
if (action == null) throw new ArgumentNullException("action");
foreach (T element in list)
{
action(element);
}
}
Test method
[TestMethod]
public void BasicForEachTest()
{
int[] numbers = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
numbers.ForEach(num =>
{
num = 0;
});
Assert.AreEqual(0, numbers.Sum());
}
Why would numbers.Sum() be equal to 55 and not 0?
num is the copy of the value of the current element you are iterating over. So you are just changing the copy.
What you do is basically this:
foreach(int num in numbers)
{
num = 0;
}
Surely you do not expect this to change the content of the array?
Edit: What you want is this:
for (int i in numbers.Length)
{
numbers[i] = 0;
}
In your specific case you could maintain an index in your ForEach extension method and pass that as second argument to the action and then use it like this:
numbers.ForEachWithIndex((num, index) => numbers[index] = 0);
However in general: Creating Linq style extension methods which modify the collection they are applied to are bad style (IMO). If you write an extension method which cannot be applied to an IEnumerable<T> you should really think hard about it if you really need it (especially when you write with the intention of modifying the collection). You have not much to gain but much to loose (like unexpected side effects). I'm sure there are exceptions but I stick to that rule and it has served me well.
Because num is a copy.
It's as if you were doing this:
int i = numbers[0];
i = 0;
You wouldn't expect that to change numbers[0], would you?
Because int is a value type and is passed to your extension method as a value parameter. Thus a copy of numbers is passed to your ForEach method. The values stored in the numbers array that is initialized in the BasicForEachTest method are never modified.
Check this article by Jon Skeet to read more on value types and value parameters.
I am not claiming that the code in this answer is useful, but (it works and) I think it illustrates what you need in order to make your approach work. The argument must be marked ref. The BCL does not have a delegate type with ref, so just write your own (not inside any class):
public delegate void MyActionRef<T>(ref T arg);
With that, your method becomes:
public static void ForEach2<T>(this T[] list, MyActionRef<T> actionRef)
{
if (actionRef == null)
throw new ArgumentNullException("actionRef");
for (int idx = 0; idx < list.Length; idx++)
{
actionRef(ref list[idx]);
}
}
Now, remember to use the ref keyword in your test method:
numbers.ForEach2((ref int num) =>
{
num = 0;
});
This works because it is OK to pass an array entry ByRef (ref).
If you want to extend IList<> instead, you have to do:
public static void ForEach3<T>(this IList<T> list, MyActionRef<T> actionRef)
{
if (actionRef == null)
throw new ArgumentNullException("actionRef");
for (int idx = 0; idx < list.Count; idx++)
{
var temp = list[idx];
actionRef(ref temp);
list[idx] = temp;
}
}
Hope this helps your understanding.
Note: I had to use for loops. In C#, in foreach (var x in Yyyy) { /* ... */ }, it is not allowed to assign to x (which includes passing x ByRef (with ref or out)) inside the loop body.
Let say I got this function :
void int Calculate(double[] array) {}
And in my main I got this array:
double[,] myArray = new double[3,3];
How can I call Calculate(...) ?
I try (that's don't compile) :
double[] mySingleArray = myArray[0];
What I want to avoid is unnecessary loop (for).
I declare a regular array, but if a jagged array or any other type of array works better, it's fine for me.
I use c# 3.5
First, let's declare your Calculate() method like this:
int Calculate(IEnumerable<double> doubles)
Don't worry, you can still pass an array to that code. You might also need IList<double>, but 9 times out of 10 the IEnumerable is good enough. The main thing is that this will let us use the yield keyword to slice up your array in an efficient way:
public static IEnumerable<T> Slice(this T[,] values)
{
return Slice(values, 0, 0);
}
public static IEnumerable<T> Slice(this T[,] values, int index)
{
return Slice(values, 0, index);
}
public static IEnumerable<T> Slice(this T[,] values, int dimension, int index)
{
int length = values.GetUpperBound(dimension);
int[] point = new int[values.Rank];
point[dimension] = index;
dimension = 1 - dimension;// only works for rank == 2
for (int i = 0; i < length; i++)
{
point[dimension] = i;
yield return (T)values.GetValue(point);
}
}
It still needs some work because it only works with rank 2 arrays, but it should be fine for the example you posted.
Now you can call your calculate function like this:
Calculate(myArray.Slice(0));
Note that due to the way IEnumerable and the yield statement work the for loop in the code I posted is essentially free. It won't run until you actually iterate the items in your Calculate method, and even there runs in a "just-in-time" fashion so that the whole algorithm remains O(n).
It gets even more interesting when you share what your Calculate method is doing. You might be able to express it as a simple Aggregate + lambda expression. For example, let's say your calculate method returned the number of items > 5:
myArray.Slice(0).Count(x => x > 5);
Or say it summed all the items:
myArray.Slice().Sum();
A jagged array works the way you want:
double[][] jaggedArray = new double[][100];
for (int i = 0; i < jaggedArray.Length; ++i)
jaggedArray[i] = new double[100];
myFunction(jaggedArray[0]);
You can have different sizes for each array in this way.
A jagged array would let you split out the first array!
The Slice() method given above will get you a single row from your array, which seems to match the sample given in your question.
However, if you want a one dimensional array that contains all the elements in the rectangular array, you can use something like this, which is also O(n).
public static T[] Flatten<T>(this T[,] array)
where T : struct
{
int size = Marshal.SizeOf(array[0, 0]);
int totalSize = Buffer.ByteLength(array);
T[] result = new T[totalSize / size];
Buffer.BlockCopy(array, 0, result, 0, totalSize);
return result;
}