I have a list of Points. List<Point> points = new List<Point>();
I want to get the biggest value of y coordinates inside the list, given the condition that it only scans the coordinates inside the list with a specific x coordinate.
For example:
I have points like this
(1,1)
(1,2)
(1,3)
(1,4)
(1,5)
(2,1)
(2,2)
(2,3)
(2,4)
(2,5)
I want to find the biggest value of y-axis or y-coordinate, given that it only search coordinates with 2 as value of x. so the output must be (2,5)
Use LINQ to get point with biggest Y coordinate:
Point maximumPoint = points.First(p => p.X == 2 &&
p.Y == points.Max(po => po.Y));
OR
Point maximumPoint = new Point(2, points.Where(p => p.X == 2).Max(p => p.Y));
With LINQ, you can do:
var result = points.Where(point => point.X == 2)
.Max(point => point.Y);
If you want the Point instead of just the Y-coordinate, it's simple enough to just new up a Point wih (2, result).
But in more complex cases, consider a MaxBy operator, such as the one that comes with morelinq.
With linq, this would by
var maxY = points.Where(p => p.X == 2).Select(p=> p.Y).Max();
This perhaps:
var maxY = points.Where(po => po.X == 2).Max(po => po.Y);
var q = points.Where(p =>
p.Y == maxY &&
p.X == 2).FirstOrDefault();
Related
I have a BaseVals series acquired from sql by a linq query on my chart. I need to put tolerance boundaries on the chart also depending on this BaseVals series' Y points.
X points of these boundary series will remain same. I am using below code for querying
int max1 = dataContext.SupplierVals
.Where(m => m.MouldID == mouldId && m.Plane == plane)
.Max(m => m.MeasId);
var query = dataContext.SupplierVals
.Where(m => m.MouldID == mouldId
&& m.MeasId == max1).ToList();
if (cbBenchType.SelectedIndex == 0)
{chartBench.Series["BaseVals"].Points.DataBind(query, "Distnc", "Apert", null);
}
How can i add 2 series (y points of the series "BaseVals" + 0.1) and
(y points of the series "BaseVals" - 0.1)?
I have a two dimensional array containing objects of type MyObj.
private MyObj[,] myObjs = new MyObj[maxX, maxY];
I want to get the indices from the array when passing in a matching object. I want to get the x and y value from this array. I can return these two values as a Position object that takes a x and y coordinate.
private Position GetIndices(MyObj obj)
{
for (int x = 0; x < myObjs.GetLength(0); x++)
{
for (int y = 0; y < myObjs.GetLength(1); y++)
{
if (myObjs[x, y] == obj)
{
return new Position(x, y);
}
}
}
}
Is it possible to get this code shorten to some Linq code lines?
But I don't think, it looks nice :)
var result = Enumerable.Range(0, myObjs.GetLength(0))
.Select(x => Enumerable.Range(0, myObjs.GetLength(1)).Select(y => new { x, y }))
.SelectMany(o => o)
.FirstOrDefault(o => myObjs[o.x, o.y] == obj);
Here's another option, if you're interested. It uses an indexer inside the first select and does a little math to find where that index falls inside the two-dimensional array.
var o = new MyObj();
myObjs[1,2] = o;
var p = myObjs.Cast<MyObj>()
.Select((x,i) => Tuple.Create(x,i))
.Where(x => x.Item1 == o)
.Select(x => new Point(x.Item2 / myObjs.GetLength(1), x.Item2 % myObjs.GetLength(1)))
.SingleOrDefault();
Console.WriteLine(p); // prints {X=1,Y=2}
It sorta looks like you're considering the x-coordinate to be the height of the array, and the y-coordinate the width, in which case you'd want to switch it up slightly:
var p = myObjs.Cast<MyObj>()
.Select((x,i) => Tuple.Create(x,i))
.Where(x => x.Item1 == o)
.Select(x => new Point(x.Item2 % myObjs.GetLength(1), x.Item2 / myObjs.GetLength(1)))
.SingleOrDefault();
Console.WriteLine(p); // prints {X=2,Y=1}
I used Point instead of Position since it's built into .NET but you should be able to just swap one for the other.
Yes, that is possible. You can ask Resharper to do the job (loop to linq) for you. After installation, just use the feature.
I want to group a pointcloud based on 2 conditions
simple on Y so I wrote pointcloudH.GroupBy(KVP => KVP.Value.Y) where KVP is an KeyValuePair<string,System.Drawing.Point>
and now I want to group it also by X if X == (previousX + 1)
as far as I know I should us ThenBy() but what do I have to write between the brackets?
and here an example for a better illustration what I want to achieve
Sample pointcloud
(x|y) (1|1),(2|1),(4|1),(1|2),(2|3),(3|3),(4|3),(5|8),(9|10)
after step 1. it looks like this
group1 (1|1),(2|1),(4|1)
group2 (1|2)
group3 (2|3),(3|3),(4|3)
group4 (5|8)
group5 (9|10)
after step 2. it should look like this
group1 (1|1),(2|1)
group2 (4|1)
group3 (1|2)
group4 (2|3),(3|3),(4|3)
group5 (5|8)
group6 (9|10)
current code
var Hgroup = pointcloudH.OrderBy(KVP => KVP.Value.Y) // order by Y
.GroupBy(KVP => KVP.Value.Y) // groub by Y
.ThenBy(KVP => KVP.Value.X); // group by X ???
I don't think LINQ is the best tool for this kind of job, but it can be achieved. The important part is to think of the relation between your Point.X and the index of the relative Point in the Point.Y group. Once you realize you want to group them by Point.X - Index, you can do:
var Hgroup = pointcloudH.OrderBy(p => p.Y)
.GroupBy(p => p.Y)
.SelectMany(yGrp =>
yGrp.Select((p, i) => new {RelativeIndex = p.X - i, Point = p})
.GroupBy(ip => ip.RelativeIndex, ip => ip.Point)
.Select(ipGrp => ipGrp.ToList()))
.ToList();
Note that this will probably perform worst than a regular iterative algorithm. My pointcloudH is an array, but you can just change the lambda to reflect your own list. Also, remove the ToList() if you want to defer execution. This was to ease the result inspection in the debugger.
If you want to group all points in a Point.Y group regardless of their index (ie order by Point.X as well. Add ThenBy(p => p.X) after the first OrderBy clause.
Your problem cannot be solved by doing 2 separate group by clauses. I have created a little sample which should work for your problem. These are the key things that are happening in the code:
Construct 'mirror' array and insert a copy of the first item at index 0, this is used to keep track of the previous point
Create a variable that is incremented whenever a 'chain' is broken. This is whenever the next value is not equal to the previous + 1. This way we can group by an unique key per 'chain'.
class Program
{
public struct Point
{
public static Point Create(int x, int y)
{
return new Point() { X = x, Y = y };
}
public int X { get; set; }
public int Y { get; set; }
public override string ToString()
{
return string.Format("({0}|{1})", X, Y);
}
}
static void Main(string[] args)
{
//helper to avoid to much keystrokes :)
var f = new Func<int, int, Point>(Point.Create);
//compose the point array
//(1|1),(2|1),(4|1),(1|2),(2|3),(3|3),(4|3),(5|8),(9|10)
var points = new[] { f(1, 1), f(2, 1), f(4, 1), f(1, 2), f(2, 3), f(3, 3), f(4, 3), f(5, 8), f(9, 10) }.OrderBy(p => p.Y).ThenBy(p => p.X);;
//create a 'previous point' array which is a copy of the source array with a item inserted at index 0
var firstPoint = points.FirstOrDefault();
var prevPoints = new[] { f(firstPoint.X - 1, firstPoint.Y) }.Union(points);
//keep track of a counter which will be the second group by key. The counter is raised whenever the previous X was not equal
//to the current - 1
int counter = 0;
//the actual group by query
var query = from point in points.Select((x, ix) => new { current = x, prev = prevPoints.ElementAt(ix) })
group point by new { point.current.Y, prev = (point.prev.X == point.current.X - 1 ? counter : ++counter) };
//method chaining equivalent
query = points.Select((x, ix) => new { current = x, prev = prevPoints.ElementAt(ix) })
.GroupBy(point => new { point.current.Y, prev = (point.prev.X == point.current.X - 1 ? counter : ++counter) });
//print results
foreach (var item in query)
Console.WriteLine(string.Join(", ", item.Select(x=> x.current)));
Console.Read();
}
}
I have a problem. I'm finding an intersection using the code below:
Envelope[][] extents = new Envelope[tilesCountX][tilesCountY];
// some code here to set "extents" values
var intersectedTiles =
extents
.SelectMany(es => es)
.Where(e => EnvIntersects(e, bounds))
.ToList();
private static bool EnvIntersects(Envelope e1, Envelope e2)
{
return e1.MinX >= e2.MinX && e1.MaxX <= e2.MaxX && e1.MinY >= e2.MinY && e1.MaxY <= e2.MaxY;
}
It works but I want to get the indexes of intersected extents.
e.g.
If extents[2][7] is an intersected element, I want to get 2 and 7.
Is it possible by modifying my code?
[edit]
bounds is an Envelope that has MinX, MinY, MaxX and MaxY properties inside.
Envelope bounds = new Envelope();
bounds.MinX = some_value_1;
bounds.MaxX = some_value_2;
bounds.MinY = some_value_3;
bounds.MaxY = some_value_4;
I think this could also give you what you want:
var intersectedIndices =
from x in Enumerable.Range(0, tilesCountX)
from y in Enumerable.Range(0, tilesCountY)
where EnvIntersects(extents[x, y], bounds)
select new { x, y };
Try this:
var intersectedTiles =
extents
.SelectMany((es,i) => es.Select((x,j)=>new{I=i,J=j,Element = x}))
.Where(e => EnvIntersects(e.Element, bounds))
.ToList();
where for all elements in intersectedTiles this is true:
intersectedTiles[x].Element == extents[intersectedTiles[x].I][intersectedTiles[x].J]
I have a List of objects which are ordered. I would like to remove redundant objects where redundant does not necessarily mean duplicate. Here is an example:
List<Point> points = new List<Point>
{
new Point(0, 10),
new Point(1, 12),
new Point(2, 16),
new Point(3, 16),
new Point(4, 16),
new Point(5, 13),
new Point(6, 16),
};
I am interested in removing the new Point(3, 16) entry because it doesn't provide useful information; I already know that the element at 2=16 and the element at 4=16. The information that 3=16 doesn't do me any good in my application (because I already have the bounds {2,4}=16), so I would like to remove that entry. I'd also like to not that I want to keep the 5th and 6th entry because there are not consecutive entries where Y=16.
Is there a slick way to do this with linq?
What about this?
public void Test()
{
List<Point> points = new List<Point>
{
new Point(0, 10),
new Point(1, 12),
new Point(2, 16),
new Point(3, 16),
new Point(4, 16),
new Point(5, 13),
new Point(6, 16),
};
var subSetOfPoints = points.Where(p=> !IsInTheMiddleX(p, points));
}
private bool IsInTheMiddleX(Point point, IEnumerable<Point> points)
{
return points.Any(p => p.X < point.X && p.Y == point.Y) &&
points.Any(p => p.X > point.X && p.Y == point.Y);
}
Edit: This gives you the expected result. I'm grouping a List<Point>(ordered by Point.X) by Point.Y. Then i take the first and last Point in each group:
var result = points.OrderBy(p => p.X)
.GroupBy(p => p.Y)
.Select(grp =>
grp.Where((p, index) => index == 0 || index == grp.Count() - 1))
.SelectMany(p => p).OrderBy(p => p.X)
.ToList();
I'd define your own class that wraps a List<Point> so that you can implement your own logic, defining what is "redundant" or other rules you wish to adhere to. It seems this would be more sane than using LINQ to handle this.
Here is my try, It works fine but the code needs to be better:
var distinctY = points.Select(p => p.Y).Distinct().ToList();
List<Point> filtered = new List<Point>();
foreach (var y in distinctY)
{
int minX, maxX;
minX = points.Where(p => p.Y == y).Min(x => x.X);
maxX = points.Where(p => p.Y == y).Max(x => x.X);
filtered.Add(new Point(minX, y));
if ( maxX != minX)
filtered.Add(new Point(maxX, y));
}
As the name LINQ indicates, it should be used only to Query the data.
If I were you I would not use LINQ to delete or modify the List. I use it only to Query it.