Back from interview. I share with you and a good and precise answer is welcome.
The purpose, you have a static method, this method receive an IList<int> you have
to get back the values you can divise by 3 and make the code.
Constraint :
The original list (in the main) has a reference on the stack and the values on the heap,
the result must be return (it's a void method) in the same space (on the heap) than the original list. The solution show here is not correct because in the method a new pointer
on the stack + heap are created in the method domain. Solution ?
Bonus : how change the code to receive not only int but float, double, ....
static void Main(string[] args)
{
IList<int> list = new List<int>() { 9, 3, 10, 6, 14, 16, 20};
CanBeDivedByThree(list);
}
static void CanBeDivedByThree(IList<int> list)
{
list = (from p in list
where p % 3 == 0
orderby p descending
select p).ToList<int>();
}
That's meaningless as the internal storage to an IList is not under your control. Adding (or possibly removing) items might re-allocate the internal data structures.
It is especially meaningless as the list in your sample contains value types which are copied anyway when you access them.
Last but not least it's basically the whole point of using a managed language that you don't have to worry about memory (al)locations. Such things are implementation details of the platform.
To take up on your bonus question: There is no simple way to achieve that. One could think that using generics with a type constraint would solve the problem here (something like static void CanBeDivedByThree<T>(IList<T> list) where T : struct), but the problem is that C# does not (yet?) have support for generic arithmetic. C# doesn't have a modulo operator that can take a generic parameter of type 'T' and 'int'.
list.RemoveAll(n => n % 3 == 0);
or
for (int i = list.Count - 1; i >= 0; --i)
{
if (list[i] % 3 != 0)
list.RemoveAt(i);
}
The first approach works only for List<T>.
One could make it a template method, but remainder operation doesn't make much sense on floats.
Unfortunately only List but not IList does implement RemoveAll. So I first implement it as an extension method.
public static int RemoveAll<T>(this IList<T> list, Predicate<T> match)
{
if (match == null)
throw new ArgumentNullException("match");
int destIndex=0;
int srcIndex;
for(srcIndex=0;srcIndex<list.Count;srcIndex++)
{
if(!match(list[srcIndex]))
{
//if(srcIndex!=destIndex)//Small optimization, can be left out
list[destIndex]=list[srcIndex];
destIndex++;
}
}
for(int removeIndex=list.Count-1;removeIndex>=destIndex;removeIndex--)
{
list.RemoveAt(removeIndex);
}
return srcIndex-destIndex;
}
Then you can use:
list.RemoveAll(n => n % 3 != 0);
You can then use overloads for other types. Unfortunately you can't (easily) make it generic since generics don't work with operator overloading.
Others have covered the list part - this is just for the bonus bit.
You can't do this in a statically typed way using C# generics, but if you're using C# 4 you can do it with dynamic typing. For example:
using System;
using System.Collections.Generic;
class Test
{
static void Main()
{
ShowDivisibleBy3(new List<int> { 1, 3, 6, 7, 9 });
ShowDivisibleBy3(new List<decimal> { 1.5m, 3.3m, 6.0m, 7m, 9.00m });
}
static void ShowDivisibleBy3<T>(IEnumerable<T> source)
{
foreach (dynamic item in source)
{
if (item % 3 == 0)
{
Console.WriteLine(item);
}
}
}
}
Related
I am pretty new to C# and I see a lot of code where I'm not quite familiar with the syntax. So I was wondering if there's some simpler way of doing what I did here:
I have a class with various properties and functions. One of them is public int gettypeforitem(int i) which returns an integer.
I want to define a property of type int[] that returns an array of the types of all items.
I come from C++, so the following code seems logic to me, but I was wondering if there's a more "straight forward" way in doing this in C#.
Thank you!
public int[] type
{
get
{
List<int> _list = new List<int>();
for(uint i=0; i<NumberOfItems;i++)
_list.Add(gettypeforitem(i));
return _list.ToArray();
}
}
LINQ is the way forward here, I'd say:
public int[] Types => Enumerable.Range(0, NumberOfItems)
.Select(i => GetTypeForItem(i))
.ToArray();
I've changed the names to follow .NET naming conventions, and this is using C# 6's expression-bodied property syntax.
As this is doing a relatively large amount of work for a property - generating a new array every call, for a start - you might want to consider making it a method instead:
public int[] GetTypes() => Enumerable.Range(0, NumberOfItems)
.Select(i => GetTypeForItem(i))
.ToArray();
As noted in comments elsewhere, you may be able to use a method group conversion for the argument to the Select method:
public int[] GetTypes() => Enumerable.Range(0, NumberOfItems)
.Select(GetTypeForItem)
.ToArray();
The exact rules for when method group conversions are valid as arguments always elude me, so I won't try to summarise them here. (They've changed over time, too.)
public int[] type
{
get
{
return Enumerable.Range(0, NumberOfItems).Select(gettypeforitem).ToArray();
}
}
Update:
As suggested in comments its better to keep C# naming standards:
public int[] Types
{
get
{
return Enumerable.Range(0, NumberOfItems).Select(getTypeForItem).ToArray();
}
}
Since you know the number of items, you can create an array straight away:
int[] _arr = new int[NumberOfItems];
for(uint i=0; i<NumberOfItems;i++)
_arr[i] = gettypeforitem(i);
return _arr;
Or if you don't care about the overhead:
Enumerable.Range(0, NumberOfItems).Select(gettypeforitem).ToArray();
Does the return type of the property have to be really an array? If not, you can alternatively also use this:
public IEnumerable<int> type
{
get
{
for(uint i=0; i<NumberOfItems;i++)
yield return gettypeforitem(i);
}
}
and then:
myObject.type.ToArray();
I am trying to add an extension to Enumerable class. but it seems that the extension FindEven() is not picked by the C# compiler. When I build, the compiler spit error :
CS0117 'Enumerable' does not contain a definition for 'FindEven'
Here is my code:
namespace ConsoleApp1
{
static public class Program
{
static IEnumerable<int> FindEven(this IEnumerable<int> array, Func<int, bool> predicte)
{
foreach (var n in array)
{
if (predicte(n))
{
yield return n;
}
}
}
static public void Main(string[] args)
{
int[] numbers = new[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var result = Enumerable.Select(Enumerable.FindEven(numbers, n => n % 2 == 0), n => n);
foreach (var output in result)
Console.WriteLine(output);
Console.ReadLine();
}
}
}
Anything I did incorrectly here?
[edit]
What I am trying to do here is to see how the 'where' statement in the following LINQ works by making my own version of 'Where', which in this case is 'FindEven' (not a good name I have to admit).
var result = from element in numbers
where element % 2 == 0
select element;
I think if I replace 'FindEven' by 'Where' which is defined in Enumerable[from metadata]... It should be the way LINQ works. But I just can not get the code compiled.
Thanks
Per your edit, it seems you're trying to add your FindEven function to the Enumerable class, but that won't work. When you're calling Enumerable.Where, you're not calling an extension method, you're calling an actual static method that's defined in Enumerable. You can't extend that class that way, because extension methods can't extend static methods, that's not what they're for. They extend instance methods.
The equivalent in your code of calling Enumerable.Where is calling Program.FindEven. That's where the static method is defined. The magic of extension methods is having both Where and FindEven available for an instance of IEnumerable<int>, regardless of where they're defined.
Pre-edit
From the way you call the method, you seem to believe that the extension method adds a new static method to the Enumerable class. It doesn't work that way. The extension method you defined will "add" the method to any instance of IEnumerable<int>, so your code will look like this:
var result = numbers.FindEven(n => n % 2 == 0);
Note, though, that your FindEven doesn't actually FindEven - it just queries using the provided predicate, meaning it's exactly the same as the built-in LINQ Where function. A proper FindEven method would be:
static IEnumerable<int> FindEven(this IEnumerable<int> source)
{
return source.Where(n => n % 2 == 0);
}
This will return a lazily-evaluated IEnumerable<int> containing only the even numbers.
Also, your external Select method does nothing - it just maps every integer to itself, meaning it returns an enumerable that's completely equivalent to its input.
When you define an extension method, you have to call it as it was a member function of your this IEnumerable<int> array parameter
simply replace your call with
var result = Enumerable.Select(numbers.FindEven(n => n % 2 == 0), n => n);
Also note that you created an extension method for IEnumerable<int>, not for Enumerable class
As per your edit, you can use Where function.
namespace ConsoleApp1
{
static public class Program
{
static public void Main(string[] args)
{
int[] numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var result = numbers.Where(n => n % 2 == 0);
foreach (var output in result)
Console.WriteLine(output);
Console.ReadLine();
}
}
}
I am trying to implement a generic Mergesort algorithm in C#, but I am having difficulty with the Constraints. I have searched many references but I can't find any that are implementing the algorithm like I am.
MergeSort algorithm in C#
Generic Implementation of Sorting Algorithms
Anyways, I am trying to provide an implementation that only allows the user to Mergesort a dataset that inherits from the IComparable interface.
Below is what I have so far:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SortUtil
{
class Program
{
static void Main(string[] args)
{
List<int> testList = new List<int> { 1, 5, 2, 7, 3, 9, 4, 6 };
Mergesort.mergeSort<int>(testList); // Compiler Error at this Line.
}
}
class Mergesort
{
public static void mergeSort<T>(ref List<T> inputData)
where T: IComparable<T>
{
mergeSort(ref inputData, 0, inputData.Count - 1);
}
private static void mergeSort<T>(ref List<T> inputData, int firstIndex, int lastIndex)
where T: IComparable<T>
{
// If the firstIndex is greater than the lastIndex then the recursion
// has divided the problem into a single item. Return back up the call
// stack.
if (firstIndex >= lastIndex)
return;
int midIndex = (firstIndex + lastIndex) / 2;
// Recursively divide the first and second halves of the inputData into
// its two seperate parts.
mergeSort(ref inputData, firstIndex, midIndex);
mergeSort(ref inputData, midIndex + 1, lastIndex);
// Merge the two remaining halves after dividing them in half.
merge(ref inputData, firstIndex, midIndex, lastIndex);
}
private static void merge<T>(ref List<T> inputData, int firstIndex, int midIndex, int lastIndex)
where T: IComparable<T>
{
int currentLeft = firstIndex;
int currentRight = midIndex + 1;
T[] tempData = new T[(lastIndex - firstIndex) + 1];
int tempPos = 0;
// Check the items at the left most index of the two havles and compare
// them. Add the items in ascending order into the tempData array.
while (currentLeft <= midIndex && currentRight <= lastIndex)
if (inputData.ElementAt(currentLeft).CompareTo(inputData.ElementAt(currentRight)) < 0)
{
tempData[tempPos++] = inputData.ElementAt(currentLeft++);
}
else
{
tempData[tempPos++] = inputData.ElementAt(currentRight++);
}
// If there are any remaining items to be added to the tempData array,
// add them.
while (currentLeft <= midIndex)
{
tempData[tempPos++] = inputData.ElementAt(currentLeft++);
}
while (currentRight <= lastIndex)
{
tempData[tempPos++] = inputData.ElementAt(currentRight++);
}
// Now that the items have been sorted, copy them back into the inputData
// reference that was passed to this function.
tempPos = 0;
for (int i = firstIndex; i <= lastIndex; i++) {
inputData.Insert(firstIndex, tempData.ElementAt(tempPos));
}
}
}
}
My issue: I am getting a Compiler error in the Main method of the Program class; however, shouldn't I have to supply the mergeSort function the parametrized type when I call it statically?
I am getting the error "The best overloaded method match for... has some invalid arguments."
I would greatly appreciate any implementation suggestions and/or any way of correcting this error. Note, I am most comfortable in Java, and since C# doesn't directly support wildcards this approach is foreign to me. Any explanations on this would be appreciated as well.
You could remove ref from all of your parameters since you do not seem to be using its functionality.
Also you would not need to provide generic parameter type in most cases because the compiler will infer the type for you. So this should work (assuming you've removed ref from the parameters) in most cases:
Mergesort.mergeSort(testList);
Also List<T> and arrays have indexers so you can get at specific elements via inputData[index] instead of ElementAt. It's just less typing that way.
MergeSort reuires a ref parameter, so it needs the ref keyword. This should work:
Mergesort.mergeSort<int>(ref testList);
The ref keyword causes an argument to be passed by reference, not by
value. The effect of passing by reference is that any change to the
parameter in the method is reflected in the underlying argument
variable in the calling method. The value of a reference parameter is
always the same as the value of the underlying argument variable.
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.
(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.