I am attempting to complete leetcode's problem #1266 (https://leetcode.com/problems/minimum-time-visiting-all-points/).
My solution works on Visual Studio just fine, but when I submit it to leetcode I encounter a compile time error :
Line 19: Char 12: error CS8320: Feature 'tuple equality' is not
available in C# 7.2. Please use language version 7.3 or greater. (in
Solution.cs)
(int, int) current = test[0];
(int, int) target = test.Last();
for (int i = 1; i < test.Count; i++)
{
target = test[i];
while (current != target) <<<<<<<<<<<<< ERROR LINE according to leetcode
I believe my VS2019 was up to date to begin with (I am now updating to the latest build : 16.3.9 --> 16.4.0) so I'm not sure what else I need to do on my end.
My question is : is there a simple alternative I could use or should I just move on? (As far as I'm concerned my solution passes - it completed the given test cases.)
Thanks for any time and help.
P.S. Sorry if you need more of my code, I'll include it if asked for. It's rather hacky and long, haha.
Instead of comparing tuples, you can compare tuples' properties:
...
// tuples current and target are not equal if either Item1 or Item2 are not equal
while (current.Item1 != target.Item1 || current.Item2 != target.Item2)
...
You may want explicit Tuple<int, int> syntax as well:
Tuple<int, int> current = test[0];
Tuple<int, int> target = test.Last();
Related
Recently I came across a code base and found some code like below
var a = 1_23_456;
Console.WriteLine(a);
I have tried to run it in visual studio 2015/ .net fiddle but it got a compilation error. But when I retried it using Roslyn 2.0 compiler, it got compiled and gives me the output 123456.
What the matter here? Why it is showing the data as an integer ?
The underscores are the digit separator. They're used to make it easier to read large numbers (particularly binary numbers). You can read about them on MSDN.
The underscores don't change the datatype. All of the following statements result in the same data type (int or System.Int32) and value:
var a = 123456;
int b = 123456;
System.Int32 c = 123456;
var d = 1_23_456;
int e = 1_23_456;
System.Int32 f = 1_23_456;
You will need the new compiler in Visual Studio 2017 to compile it, though you may be able to get away with using Visual Studio 2015.
I've started trying new features of C# 7 in Visual Studio Enterprise 15 Preview 2. I'm able to run code of other upcoming features like Binary literals, digit separators etc. But the new syntax of initialization of tuples is not working.
Here is my code snippet:
var latLong = new (double lat, double lng) { lat = 0, lng = 0 };
var result = (5, 20);
var result = (count: 5, sum: 20);
I've followed all the steps mentioned in this blog. Just posting this question if anyone else has also come across this issue. Above code results in compilation failures as shown below:
1>Program.cs(18,26,18,27): error CS1031: Type expected
1>Program.cs(18,27,18,33): error CS1525: Invalid expression term 'double'
1>Program.cs(18,34,18,37): error CS1003: Syntax error, ',' expected
1>Program.cs(18,39,18,45): error CS1525: Invalid expression term 'double'
1>Program.cs(18,46,18,49): error CS1003: Syntax error, ',' expected
I was able to figure this out from another link here. If you read through the comments section it is evident that not all new upcoming features of C# have been able to make it to last VS 15 release which was published. Tuple (value types with new declaration syntax) is one such feature.
We might have to wait for RTM build before all features can really start working OR the other way is to get the latest source code of roslyn from its gitHub repository, clone it on your own machine, compile it and make your Visual Studio 15 Preview 2 installation to use it. More latest commit you pull, more features you will get to play with.
You can initialize it this way:
void Main()
{
var latLong = (lat:0, lng:0);
var result1 = (5, 20);
var result2 = (count: 5, sum: 20);
}
To try it, you can either use the fiddle (link at the bottom of this answer), or offline with the LinqPad tool, both support C#7 already.
To view the results, add
latLong.Dump(); result1.Dump(); result2.Dump();
to the example above. All 3 declarations are created as ValueTuple<Int32,Int32>. To create other data types, you need to specify it as explicit type conversion, e.g.
var latLong = (lat:(double)0.5, lng:(double)0);
will create a ValueTuple<Double,Double>. To decompose the tuple, use
var (lat, lng) = latLong;
which will create and assign two variables lat and lng. To find out some more C#7 features, look here.
Try out examples with DotNetFiddle
So as an excercise in utility i've taken it upon myself to convert one of our poor old vb .net 1.1 apps to C# .net 4.0.
I used telerik code conversion for a starting point and ended up with ~150 errors (not too bad considering its over 20k of code and rarely can i get it to run without an error using the production source) many of which deal with time/date in vb versus c#.
my question is this how would you represent the following statement in VB
If oStruct.AH_DATE <> #1/1/1900# Then
in C#? The converter gave me
if (oStruct.AH_DATE != 1/1/1900 12:00:00 AM) {
which is of course not correct but I cannot seem to work out how to make it correct.
if (oStruct.AH_DATE != new DateTime(1900, 1, 1){
You may try this construct :
if ( DateTime.Compare(oStruct.AH_DATE, new DateTime(1900, 1, 1)) == 0 )
{
// your code here
}
Here is a reference how to compare DateTimes in .NET - DateTime.Compare Method
Note: Comparing two dates like integers may lead you to wrong results. Because, date-time structure in .NET has its specific properties. I would always try to be attentive when comparing two dates, and always choose DateTime.Compare to be on a safer side.
This should work:
if (oStruct.AH_DATE != DateTime.Parse("1/1/1900"))
ReSharper 6.0 gives me the "Access to modified closure" warning for the dr identifier in the first code snippet.
private IEnumerable<string> GetTheDataTableStrings(DataTable dt) {
foreach (DataRow dr in dt.Rows) {
yield return GetStringFuncOutput(() => dr.ToString());
}
}
I think I have a basic understanding of what this warning is trying to protect me from: dr changes several times before GetTheDataTableStrings's output is interrogated, and so the caller might not get the output/behavior I expect.
But R# doesn't give me any warning for the second code snippet.
private IEnumerable<string> GetTheDataTableStrings(DataTable dt) {
return from DataRow dr in dt.Rows select GetStringFuncOutput(dr.ToString);
}
Is it safe for me to discard this warning/concern when using the comprehension syntax?
Other code:
string GetStringFuncOutput(Func<string> stringFunc) {
return stringFunc();
}
First off, you are correct to be concerned about the first version. Each delegate created by that lambda is closed over the same variable and therefore as that variable changes, the meaning of the query changes.
Second, FYI we are highly likely to fix this in the next version of C#; this is a major pain point for developers.
(UPDATE: This answer was written in 2011. We did in fact take the fix described below in C# 5.)
In the next version each time you run through the "foreach" loop we will generate a new loop variable rather than closing over the same variable every time. This is a "breaking" change but in the vast majority of cases the "break" will be fixing rather than causing bugs.
The "for" loop will not be changed.
See http://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/ for details.
Third, there is no problem with the query comprehension version because there is no closed-over variable that is being modified. The query comprehension form is the same as if you'd said:
return dt.Rows.Select(dr=>GetStringFuncOutput(dr.ToString));
The lambda is not closed over any outer variable, so there is no variable to be modified accidentally.
The issue that Resharper is warning about has been resolved in both C# 5.0 and VB.Net 11.0. The following are extracts from the language specifications. Note that the specifications can be found in the following paths by default on a machine with Visual Studio 2012 installed.
C:\Program Files (x86)\Microsoft Visual Studio 11.0\VB\Specifications\1033\Visual Basic Language Specification.docx
C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC#\Specifications\1033\CSharp Language Specification.docx
C# Language Specification Version 5.0
8.8.4 The foreach statement
The placement of v inside the while loop is important for how it is captured by any anonymous function occurring in the embedded-statement.
For example:
int[] values = { 7, 9, 13 };
Action f = null;
foreach (var value in values)
{
if (f == null) f = () => Console.WriteLine("First value: " + value);
}
f();
If v was declared outside of the while loop, it would be shared among all iterations, and its value after the for loop would be the final value, 13, which is what the invocation of f would print. Instead, because each iteration has its own variable v, the one captured by f in the first iteration will continue to hold the value 7, which is what will be printed. (Note: earlier versions of C# declared v outside of the while loop.)
The Microsoft Visual Basic Language Specification Version 11.0
10.9.3 For Each...Next Statements (Annotation)
There is a slight change in behavior between version 10.0 and 11.0 of the language. Prior to 11.0, a fresh iteration variable was not created for each iteration of the loop. This difference is observable only if the iteration variable is captured by a lambda or a LINQ expression which is then invoked after the loop.
Dim lambdas As New List(Of Action)
For Each x In {1,2,3}
lambdas.Add(Sub() Console.WriteLine(x)
Next
lambdas(0).Invoke()
lambdas(1).Invoke()
lambdas(2).Invoke()
Up to Visual Basic 10.0, this produced a warning at compile-time and printed "3" three times. That was because there was only a single variable "x" shared by all iterations of the loop, and all three lambdas captured the same "x", and by the time the lambdas were executed it then held the number 3.
As of Visual Basic 11.0, it prints "1, 2, 3". That is because each lambda captures a different variable "x".
I'd like to know how to convert this code line by line from C# to F#. I am not looking to use any kind of F#'s idioms or something of the like. I am trying to understand how to map directly C#'s constructs to F#.
Here is the C# code:
//requires l.Length > 0
int GetMinimumValue(List<int> l) {
int minVal = l[0];
for (int i = 0; i < l.Length; ++i) {
if (l[i] > minValue) {
minVal = l[i];
}
}
return minVal;
}
And here is my F# attempt:
let getMinValue (l : int list) =
let minVal = l.Head
for i = 0 to (l.Length-1) do
if (l.Item(i) > minVal) then
minVal = col.Item(i)
minVal
Now, this ain't working. The problem seems to be related with the minVal = col.Item(i) line:
This expression was expected to have type unit but here has type bool
What is the problem, really?
If you want to convert it line by line then try the following
let getMinValue (l:System.Collections.Generic.List<int>) =
let mutable min = l.Item(0)
for i = 0 to (l.Count-1) do
if l.Item(i) < min then min <- l.Item(i)
min
Now as to why you're getting that particular error. Take a look at the following line
minVal = col.Item(i)
In F# this is not an assignment but a comparison. So this is an expression which produces a bool value but inside the for loop all expressions must be void/unit returning. Hence you receive an error.
Assignment in F# has at least 2 forms that I am aware of.
// Assigning to a mutable value
let mutable v1 = 42
v1 <- 13
// Assigning to a ref cell
let v1 = ref 0
v1 := 42
And of course, you should absolutely read Brian's article on this subject. It's very detailed and goes over many of the finer points on translating between the two languages
http://lorgonblog.spaces.live.com/Blog/cns!701679AD17B6D310!725.entry
There are a few problems with your literal translation. First of all, there's the immediate problem which causes the compiler error: as others have noted, let bindings are immutable by default. However, there's at least one other big problem: System.Collections.Generic.List<T> is very different from F#'s 't list. The BCL type is a mutable list backed by an array, which provides constant time random access to elements; the F# type is an immutable singly linked list, so accessing the nth element takes O(n) time. If you insist on doing expression-by-expression translation, you may find this blog post by Brian valuable.
I'd strongly recommend that you follow others' advice and try to acclimate yourself to thinking in idiomatic F# rather than literally translating C#. Here are some ways to write some related functions in F#:
// Given an F# list, find the minimum element:
let rec getMinList l =
| [] -> failwith "Can't take the minimum of an empty list"
| [x] -> x
| x::xs ->
let minRest = getMin xs
min x minRest
Note that this works on lists of any element type (with the caveat that the element type needs to be comparable from F#'s perspective or the application of the function will cause a compile-time error). If you want a version which will work on any type of sequence instead of just on lists, you could base it on the Seq.reduce function, which applies the function supplied as its first argument to each pair of elements in a sequence until a single value remains.
let getMin s = Seq.reduce min s
Or best of all, you can use the built-in Seq.min function, which is equivalent.
Short answer: = is not (mutable) assignment in F#.
Question: Do you really mean col?
Suggestions: Try to write this with NO assignments. There is recursion and built-in functions at your disposal :-)
You should read
What does this C# code look like in F#? (part one: expressions and statements)
I am disappointed that none of the other answers already linked it, because people ask the 'how to convert C# to F#' question a lot, and I have posted this answer link a lot, and by now some of the other answerers should know this :)
This is the most literal translation possible:
let getMinimumValue (l: List<int>) =
let mutable minVal = l.[0]
for i=0 to l.Length-1 do
if l.[i] > minVal then
minVal <- l.[i]
minVal