How to add using the 'with' keyword? - c#

public record Cube(int x, int y, int z, int w);
I recently ran across a time I was doing this:
var next = new Cube(existing.x + 1, existing.y, existing.z, existing.w);
and I thought there must be a cleaner way to add arbitrary values to the record. But when I try this:
var next = existing with { x = x+1 };
It cries because you do not have access to the values to add to. Instead I have to do this:
var next = existing with { x = existing.x+1 };
Am I just wanting too much from the with keyword?

My understanding of with syntax is exactly that - you must reference the name of the object to the left of the width statement. This seems to line up with the spec here: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/records
While the x = x + 1 is convenient, it is not very expressive on the source of where x is coming from.

The x in x = x+1 is the x of the next instance to be created. However, this instance does not yet exist at that point that's why the compiler complains. Instead, you have to state explicitly that the second x is the one of the existing instance.

Related

How to get biggest element in HashSet of object by field?

Suppose I have the class
public class Point {
public float x, y, z;
}
And I've created this hashset:
HashSet<Point> H;
How can I get the element of H with the biggest z? It doesn't need necessarily to use Linq.
You can use Aggregate to mimic MaxBy functionality (note that you need to check if collection has any elements first):
var maxByZ = H.Aggregate((point, point1) => point.z > point1.z ? point : point1);
When .NET 6 is out it should have built in MaxBy.
You could do this:
int maxZ = H.Max(point => point.Z);
var maxPointByZ = H.Where(point => point.Z == maxZ).FirstOrDefault();
This works by first retrieving the largest value of Z in the set:
H.Max(point2 => point2.Z) //Returns the largest value of Z in the set
And then by doing a simple where statement to get the record where Z is equal to that value. If there are multiple values, it will get the first one, so you may want to sort the enumerable in advance.

How to print variable's new value after it has been changed

If I have a program where x = 2 and I subtracted x by 1, making x = 1. Is there any way to make it so that whenever x will be printed in the program, it will print 1?
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int x = 2;
Console.WriteLine(x-1);
Console.WriteLine(x); //make x's new value 1
}
}
}
you need to store the calculation to the variable
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int x = 2;
Console.WriteLine(x);//will print 2
x = x-1; //applying calculation and storing to same variable
Console.WriteLine(x); //make x's new value 1 : Done
}
}
}
You are Displaying the Correct answer.
2 - 1 will Display 1. But u arent changing the Variable or even touching it. You are just using it for a Reference to Calculate what is x - 1?
Displaying only X now will Display 2 as it has NOT been changed.
Setting (Changing the Value of a Variable) is not (normaly) possible inside a Function. There are Functions which take ref params. Which will work with its memory.
You simply need a one-liner.
x = x - 1 translated the value of x is set to the value of x - 1.
it seems much for a simple calculation to require a whole line as it is. But programming will always be one of these things where u have to think literall
This whole problem is a great example for Rubberducking.
think about it literall... line for line what exactly happens and why should it not work?
Write
x--;
Console.WriteLine(x);
That's how you change the value of a variable - you have to assign it a new value.
Alternatively you can write x = x - 1; longhand instead of using the decrement (--) operator.
What you did in your version was to create some output which was the result of x-1, but that doesn't change the original value of x, it just uses x in another calculation.

ILNumerics using subarrays and matfiles with structs

First question: Can ILNumerics read matfiles with struct? I couldnt make it work.
I then split the file in matlab and I would like to use it for calculations. but i have problems with the subarray function. I would like to do this:
using (ILMatFile matRead = new ILMatFile(#"C:\Temp\Dates.mat"))
{
ILArray<double> Dates = matRead.GetArray<double>("Dates");
double x = 736055-1;
double y = 736237+1;
ILArray<ILLogical> LogDates = (Dates > x && Dates < y);
}
using (ILMatFile matRead = new ILMatFile(#"C:\Temp\Power.mat"))
{
ILArray<double> power = matRead.GetArray<double>("Power");
ILArray<double> tpower = power[LogDates, full];
double avgpower = tpower.Average();
Console.WriteLine(avgpower.ToString());
Console.ReadKey();
}
This doesnt work for a number of reasons. The logical doesnt take my syntax and I dont really get why. But also the subarry in the second block doesnt work, it doesnt know the full keyword (even though the documentation says it shouldand also it doesnt like the logical. obviously I want to average tpower over all columns and only those rows where the logical condition is one.
thanks.
nik
ILLogical is an array itself. You use it like that:
ILLogical LogDates = ILMath.and(Dates > x, Dates < y);
If you still experiencing problems with the subarray, try:
ILArray<double> tpower = power[ILMath.find(LogDates), ILMath.full];
Only, if your class is derived from ILMath, you can ommit the ILMath. identifier! Otherwise, string subarray definitions are sometimes shorter:
ILArray<double> tpower = power[ILMath.find(LogDates), ":"]
In order to take the average over selected rows, reducing to one:
double avgpower = tpower.Average(); // Linq version
double avgpower = (double)ILMath.sumall(tpower) / tpower.S.NumberOfElements; // prob. faster on large data

Extract x,y values from deldir object using RDotNet

Background
I am using RDotNet to run an R script that performs a voronoi tessellation using the deldir package. After
R:tiles = tile.list(voro) I wish to extract R:tiles[[i]][c("x","y")] for the each tile i into a C#:List<Tuple<double,double>>.
Issue 1
I can extract the R:tiles object into C#-world using var tiles = engine.Evaluate("tiles").AsVector().ToList(); but I am struggling to understand how to use RDotNet to extract the x, y values for each tile from this point:
I don't know how to iterate over this object to extract the x, y values that I desire.
Issue 2
Alternatively, I attempted to create a new simpler object in R, i.e. values and attempt to extract a string and parse values from that. So far I have only created this object for one of the points:
R: e.g.
values <- tiles[[1]][c("x","y")]
C#: e.g.
var xvalues = engine.Evaluate("values[\"x\"]").AsCharacter();
var yvalues = engine.Evaluate("values[\"y\"]").AsCharacter();
// Some boring code that parses the strings, casts to double and populates the Tuple
However I can only extract one string at a time and have to split the string to obtain the values I'm after. This does not seem like the way I should be doing things.
Question
How can extract the x,y coordinates for every tile from R:tiles[[i]][c("x","y")] into a C#:List<Tuple<double,double>>?
I think you are after something like the following if I got what you seek correctly. The full code I tested is committed to a git repo I've just set up for SO queries. I've tested against the NuGet package for 1.5.5; note to later readers that subsequent versions of R.NET may let you use other idioms.
var res = new List<List<Tuple<double, double>>>();
// w is the result of tile.list as per the sample in ?tile.list
var n = engine.Evaluate("length(w)").AsInteger()[0];
for (int i = 1; i <= n; i++)
{
var x = engine.Evaluate("w[[" + i + "]]$x").AsNumeric().ToArray();
var y = engine.Evaluate("w[[" + i + "]]$y").AsNumeric().ToArray();
var t = x.Zip(y, (first, second) => Tuple.Create(first, second)).ToList();
res.Add(t);
}

Alternatives to nested Select in Linq

Working on a clustering project, I stumbled upon this, and I'm trying to figure out if there's a better solution than the one I've come up with.
PROBLEM : Given a List<Point> Points of points in R^n ( you can think at every Point as a double array fo dimension n), a double minDistance and a distance Func<Point,Point,double> dist , write a LINQ expression that returns, for each point, the set of other points in the list that are closer to him than minDistance according to dist.
My solution is the following:
var lst = Points.Select(
x => Points.Where(z => dist(x, z) < minDistance)
.ToList() )
.ToList();
So, after noticing that
Using LINQ is probably not the best idea, because you get to calculate every distance twice
The problem doesn't have much practical use
My code, even if bad looking, works
I have the following questions:
Is it possible to translate my code in query expression? and if so, how?
Is there a better way to solve this in dot notation?
The problem definition, that you want "for each point, the set of other points" makes it impossible to solve without the inner query - you could just disguise it in clever manner. If you could change your data storage policy, and don't stick to LINQ then, in general, there are many approaches to Nearest Neighbour Search problem. You could for example hold the points sorted according to their values on one axis, which can speed-up the queries for neighbours by eliminating early some candidates without full distance calculation. Here is the paper with this approach: Flexible Metric Nearest Neighbor Classification.
Because Points is a List you can take advantage of the fact that you can access each item by its index. So you can avoid comparing each item twice with something like this:
var lst =
from i in Enumerable.Range(0, Points.Length)
from j in Enumerable.Range(i + 1, Points.Length - i - 1)
where dist(Points[i], Points[j]) < minDistance
select new
{
x = Points[i], y = Points[j]
};
This will return a set composed of all points within minDistance of each other, but not exactly what the result you wanted. If you want to turn it into some kind of Lookup so you can see which points are close to a given point you can do this:
var lst =
(from i in Enumerable.Range(0, Points.Length)
from j in Enumerable.Range(i + 1, Points.Length - i - 1)
where dist(Points[i], Points[j]) < minDistance
select new { x = Points[i], y = Points[j] })
.SelectMany(pair => new[] { pair, { x = pair.y, y = pair.x })
.ToLookup(pair => pair.x, pair => pair.y);
I think you could add some bool Property to your Point class to mark it's has been browsed to prevent twice calling to dist, something like this:
public class Point {
//....
public bool IsBrowsed {get;set;}
}
var lst = Points.Select(
x => {
var list = Points.Where(z =>!z.IsBrowsed&&dist(x, z) < minDistance).ToList();
x.IsBrowsed = true;
return list;
})
.ToList();

Categories