I have this:
public class LatLon
{
public double lat {get;set;}
public double lon {get;set;}
}
in a List<LatLon>. It contains of
p1 { lat = 49.9429989, lon = 3.9542134 }
p2 { lat = 49.9429989, lon = 3.9542133 }
p3 { lat = 49.9429989, lon = 3.9542136 }
etc..
My goal is to remove coordinates from this list whose difference to other coordinates is lower than the boundaries of lat_bound and lon_bound, so even though the person recording stood at a place for a long time, it means there is only one coordinate left. What would be the LINQ command?
Example:
p1 { lat = 4.555, lon = 6.555 }
p2 { lat = 4.556, lon = 6.556 }
.
Then Math.Abs(p1.lat - p2.lat) = 0.001 and Math.Abs(p1.lon - p2.lon) = 0.001. p1.lon - p2.lon is the lon difference to one other coordinate's lon-value. Let's say lon_bound equals 0.0005 then this very coordinate is being removed if lat_bound is also 0.0005, as 0.001 > 0.0005.
EDIT: I decided to pipe to http://www.gpsbabel.org instead.
LINQ Does not make wonders. The problem you are referring to is not just a "Distict" type problem.
1st You have to make a function to measure distance between 2 points.
2nd You need to detect clusters of points..(organize close points into groups)
Finally the easiest thing to do is to Group By a Belonging cluster and keep only 1point from each group.....
But then again.....there are several other problems which might not produce accurate results.
For example whats the one point that represents its group best?
You can use Math.Round to round the values to the precision that you want.
Then use Linq Distinct to remove the duplicates.
void Main()
{
var list = new List<Coordinate>()
{
new Coordinate(25.25251, 100.21254),
new Coordinate(25.25252, 100.21255),
new Coordinate(25.25253, 100.21256),
new Coordinate(25.80000, 100.90000)
};
int precision = 4;
var res = list.Select(x => new Coordinate(
Math.Round(x.Lon, precision),
Math.Round(x.Lat, precision))).Distinct().ToList();
}
public struct Coordinate
{
private double lon;
private double lat;
public Coordinate(double lon, double lat)
{
this.lon = lon;
this.lat = lat;
}
public double Lat { get { return lat; } }
public double Lon { get { return lon; } }
}
(Note that I have I'm using a struct and not a class for the Coordinate's)
If you have a function Func<LatLon, LatLon, bool> bounded that returns true if the two points are within your bound and false if not then this query works:
var keeps =
latlons
.Aggregate(new List<LatLon>(), (xs, y) =>
{
if (!xs.Any(x => bounded(x, y)))
{
xs.Add(y);
}
return xs;
});
You can filter by proximity like this:
public class LatLon
{
public double lat {get;set;}
public double lon {get;set;}
}
class ProximityFilter
{
private LatLon m_ref = null;
internal bool DifferentFromPrevious(LatLon arg)
{
if (m_ref == null)
{
m_ref = arg;
return true;
}
var are_different = Math.Abs(arg.lat - m_ref.lat) > 0.001 || Math.Abs(arg.lon - m_ref.lon) > 0.001;
if (are_different)
m_ref = arg;
return are_different;
}
}
class Program
{
static int Main(string[] args)
{
var p1 = new LatLon { lat = 49.9429989, lon = 3.9542134 };
var p2 = new LatLon { lat = 49.9529989, lon = 3.9642134 };
var p3 = new LatLon { lat = 49.9429989, lon = 3.9542133 };
var p4 = new LatLon { lat = 49.9429989, lon = 3.9542136 };
var list = new List<LatLon> {p1, p2, p3, p4};
var filter = new ProximityFilter();
var cleaned = list.Where(filter.DifferentFromPrevious);
// ...
}
}
You can't use Distinct as it will remove the point with a value seen before, even if there is a different value between them.
Additionally, this approach has O(N) complexity, so at least theoretically it performs better than Distinct. It also works both with structs and classes.
Related
This question already has answers here:
How to use LINQ to select object with minimum or maximum property value
(20 answers)
How to perform .Max() on a property of all objects in a collection and return the object with maximum value [duplicate]
(9 answers)
Closed 1 year ago.
first post here so I hope this is how I should ask questions here,
So, I have a function used in different classes (override), and I need to display the MaxValue of this function across different data. (don't know if I said it correcty).
Tried this first but it kept giving me the same answer even though it wasn't the max value:
class Program
{
static void Main(string[] args)
{
Trapezoid[] Shape = new Trapezoid[5];
Shape[0] = new Trapezoid(4,3.5,2);
Shape[1] = new Rectangle(9,2);
Shape[2] = new Square(5);
Shape[3] = new Trapezoid(2,6.8,10);
Shape[4] = new Square(8);
Trapezoid maximumArea = null;
foreach (Trapezoid trapezoid1 in Shape)
{
double area1 = trapezoid1.Area();
foreach (Trapezoid trapezoid2 in Shape)
{
double area2 = trapezoid1.Area();
if (area1 >= area2)
{
maximumArea = trapezoid1;
}
else
{
maximumArea = trapezoid2;
}
}
Console.WriteLine(maximumArea.ToString());
Console.ReadLine();
}
}
the second time I tried this but couldn't make it work:
class Program
{
static void Main(string[] args)
{
Trapezoid[] Shape = new Trapezoid[5];
Shape[0] = new Trapezoid(4,3.5,2);
Shape[1] = new Rectangle(9,2);
Shape[2] = new Square(5);
Shape[3] = new Trapezoid(2,6.8,10);
Shape[4] = new Square(8);
Trapezoid maximumArea = null;
foreach (Trapezoid trapezoid1 in Shape)
{
double area1 = trapezoid1.Area();
foreach (Trapezoid trapezoid2 in Shape)
{
double area2 = trapezoid2.Area();
maximumArea = Math.Max (area1 , area2);
}
}
Console.WriteLine(maximumArea.ToString());
Console.ReadLine();
}
}
the function is Area, if you need to see it:
class Trapezoid
{
protected double a,b,h;
public Trapezoid(double a, double b, double h)
{
this.a = a;
this.b = b;
this.h = h;
}
public virtual double Area()
{
return ((a + b) * h) / 2;
}
public override string ToString()
{
return "The area of this Trapezoid is " + Area() + ".";
}
}
did the same thing in rectangle and square classes by overriding (inherited classes).
I hope you can help me, thank you. :)
You need to use maximumArea to store the max of the list, not the max of the current pair.
Trapezoid maximumArea = new Square(0); //Smallest possible trapezoid
foreach (Trapezoid t in Shape)
{
if (t.Area() > maximumArea.Area()) maximumArea = t;
}
Console.WriteLine(maximumArea);
You can also shorten this considerably using LINQ:
var maximumArea = shape.OrderByDescending( x => x.Area() ).First();
And if there's a chance that some trapezoids will tie, maybe you should get a list:
var max = shape.Max( x => x.Area() );
var maximumAreas = shape.Where( x => x.Area() == max).ToList();
Use the power of Linq:
using System.Linq;
then
var trapezoidWithTheLargestArea = Shape.OrderByDescending(s => s.Area()).First()
I currently have a list of coordinates that I need sorted. Each line represents Longitude, Latitude. I need to sort only on the Longitude.
It is stored in an string array:
string[] coords = fpdp.Coordinates.ToArray();
Here is the original list:
**LongLat**
98.63,85.02
43.08,79.07
26.97,70.88
18.8,62.3
13.47,53.5
8.57,44.8
3.58,36.35
-1.63,28.2
-6.93,20.33
-12.12,12.63
-17.17,5.02
-22.63,-2.25
-28.22,-9.43
-34.98,-15.7
-42.67,-21.08
-51.18,-25.62
-60.55,-29.12
-70.7,-31.12
-81.2,-31.18
-91.42,-29.72
-101.02,-26.97
-109.62,-22.85
-117.3,-17.83
-123.9,-11.9
-129.32,-5.05
-133.55,2.47
-136.9,10.3
-140.45,17.78
-144.75,24.98
-148.6,32.53
-152.02,40.37
-155.85,48.28
-160.8,56.27
-165.75,64.48
-172.62,72.78
171.35,80.83
98.93,85.17
Here is what I need it to look like. It is sorted by Large to small for positive numbers, and small to large for negative numbers. Only focusing on the first longitude coordinate:
**LongLat-Sorted**
171.35,80.83
98.93,85.17
98.63,85.02
43.08,79.07
26.97,70.88
18.8,62.3
13.47,53.5
8.57,44.8
3.58,36.35
-1.63,28.2
-6.93,20.33
-12.12,12.63
-17.17,5.02
-22.63,-2.25
-28.22,-9.43
-34.98,-15.7
-42.67,-21.08
-51.18,-25.62
-60.55,-29.12
-70.7,-31.12
-81.2,-31.18
-91.42,-29.72
-101.02,-26.97
-109.62,-22.85
-117.3,-17.83
-123.9,-11.9
-129.32,-5.05
-133.55,2.47
-136.9,10.3
-140.45,17.78
-144.75,24.98
-148.6,32.53
-152.02,40.37
-155.85,48.28
-160.8,56.27
-165.75,64.48
-172.62,72.78
How can I accomplish this in code? Any help would be great.
SOLUTION:
I tweaked this to the following, and it's working. Thanks a lot! :)
public class LongLatSort : IComparer
{
int IComparer.Compare(Object x, Object y)
{
string[] longLatParts1 = Convert.ToString(x).Split(',');
string[] longLatParts2 = Convert.ToString(y).Split(',');
var var1 = double.Parse(longLatParts1[0]);
var var2 = double.Parse(longLatParts2[0]);
if (var1 > var2)
{
return -1; // flipped for descending
}
else if (var1 < var2)
{
return 1; // flipped for descending
}
// secondary sort on latitude when values are equal
return var1 > var2 ? -1 : 1; // flipped for descending
}
}
Just finished tested this, seems to work.
class SimplePoint
{
public SimplePoint(string coord)
{
var coords = coord.Split(',').Select(s => double.Parse(s, System.Globalization.CultureInfo.InvariantCulture)).ToArray();
X = coords[0];
Y = coords[1];
}
public double X;
public double Y;
public override string ToString()
{
return X.ToString() + "," + Y.ToString();
}
}
static class LongLatParseAndSort
{
public static string SortedLongLat(string unsorted)
{
return unsorted
.Split(' ')
.Select(c => new SimplePoint(c))
.OrderByDescending(sp => sp.X)
.Select(sp => sp.ToString())
.Aggregate((a, b) => a += b);
}
}
How is this data stored? An array of Strings? or a 2-dimensional array or floats? or an Array of some structure with a lat and long? I'll assume its an array of LongLat since thats how you worded it.
EDIT I realized your subject title said string, so I added a constructor to convert from string to a LongLat.
Your desired result looks sorted descending on Longitude.
This code is untested, forgive me if it's not 100% but you get the idea.
// This is pretending to be the data structure you are using
public class LongLat {
private float mLongitude;
private float mLatitude;
// constructor from string for convenience
public LongLat(string longLatString ) {
string[] longLatParts = longLatString.Split(',');
mLongitude = float.Parse(longLatParts[0]);
mLatitude = float.Parse(longLatParts[1]);
}
public float Longitude {get; set; }
public float Latitude {get; set; }
}
// The sorter
public class LongLatSort : IComparer {
public int IComparer.Compare(object a, object b) {
LongLat o1=(LongLat)a;
LongLat o2=(LongLat)b;
if (o1.Longitude > o2.Longitude) {
return -1; // flipped for descending
} else if ( o1.Latitude < o2.Longitude ) {
return 1; // flipped for descending
}
// secondary sort on latitude when values are equal
return o1.Latitude > o2.Latitude ? -1 : 1; // flipped for descending
}
}
// now you should be able to use the sorter something like this?
// though best to not instantiate the Comparer every time but you get the idea
// EDIT: create your array of LongLats from strings first
Arrays.Sort( yourArrayofLongLats, new LongLastSort() );
The setup for my List and the item class are as such:
public class mapVertex {
public Vector2 vertex;
public float x {
get{ return vertex.x; }
}
public float z {
get{ return vertex.y; }
}
public mapVertex(float x, float y) {
myID = ID++;
vertex.x = x;
vertex.y = y;
}
}
void Start() {
...
vertexList = new List<mapVertex>();
for (...)
vertexList.Add( new mapVertex( (float) 10.1, (float) 11.2 ) );
Following immediately in the code is the Find statement. After execution of the below however newEdge.B is equal to null.
for (...)
mapEdge newEdge = new mapEdge();
double[] vve = new double[2];
vve[0] = 10.1;
vve[1] = 11.2;
newEdge.B = vertexList.Find( x => (x.x == (float) vve[0]) && (x.z == (float) vve[1]) );
...
}
The below evaluates to true in the expression evaluator in MonoDevelop when I breakpoint on the line in question and the debugger confirms the values look correct, so I'm not sure why List.Find() isn't returning the first element of vertexList.
(vertexList[0].x == (float) vve[0]) && (vertexList[0].z == (float) vve[1])
Is this possibly related to a type conversion issue? The values of the items in vertexList were originally created by casting double to float (see above), but from what I understand doubles should be deterministic when casting to float.
Edit:
When changing
double[] vve = new double[2];
vve[0] = 10.1;
vve[1] = 11.2;
to
float[] vve = new float[2];
vve[0] = 10.1f;
vve[1] = 11.2f;
this seems to work..
Anyone know why?
I have latitude and longitude points like(23.7019973789308,72.5465551902882)
like this, I have many point, who are enter by Users in my application,
I just want to convert them in Meters in 43 Zone in C#.
I did't get any suitable code, who can convert these points.
I go through this link also, but did't get solution.
http://www.igorexchange.com/node/927
I tried this code also....
static public IPoint FromLatLonToUTM(double lon, double lat, out double UTM_x, out double UTM_y)
{
ISpatialReferenceFactory2 pSpatRefFact;
IProjectedCoordinateSystem pToPCS;
IGeographicCoordinateSystem pFromGCS;
IGeometry pGeo ;
IPoint pPoint;
UTM_x = 0;
UTM_y = 0;
pPoint = new PointClass();
pPoint.PutCoords(lon, lat);
pSpatRefFact = new SpatialReferenceEnvironmentClass();
pFromGCS = pSpatRefFact.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_NAD1983);
pToPCS = pSpatRefFact.CreateProjectedCoordinateSystem((int)esriSRProjCSType.esriSRProjCS_NAD1983UTM_17N);
pGeo = pPoint;
pGeo.SpatialReference = pFromGCS;
pGeo.Project (pToPCS);
pPoint = (IPoint) pGeo;
UTM_x = pPoint.X;
UTM_y = pPoint.Y;
Debug.Write(UTM_x);
Debug.WriteLine("");
Debug.Write(UTM_y);
Debug.WriteLine("");
return pPoint;
}
Help me.............
class FxRate {
string Base { get; set; }
string Target { get; set; }
double Rate { get; set; }
}
private IList<FxRate> rates = new List<FxRate> {
new FxRate {Base = "EUR", Target = "USD", Rate = 1.3668},
new FxRate {Base = "GBP", Target = "USD", Rate = 1.5039},
new FxRate {Base = "USD", Target = "CHF", Rate = 1.0694},
new FxRate {Base = "CHF", Target = "SEK", Rate = 8.12}
// ...
};
Given a large yet incomplete list of exchange rates where all currencies appear at least once (either as a target or base currency): What algorithm would I use to be able to derive rates for exchanges that aren't directly listed?
I'm looking for a general purpose algorithm of the form:
public double Rate(string baseCode, string targetCode, double currency)
{
return ...
}
In the example above a derived rate would be GBP->CHF or EUR->SEK (which would require using the conversions for EUR->USD, USD->CHF, CHF->SEK)
Whilst I know how to do the conversions by hand I'm looking for a tidy way (perhaps using LINQ) to perform these derived conversions perhaps involving multiple currency hops, what's the nicest way to go about this?
First construct a graph of all your currencies:
private Dictionary<string, List<string>> _graph
public void ConstructGraph()
{
if (_graph == null) {
_graph = new Dictionary<string, List<string>>();
foreach (var rate in rates) {
if (!_graph.ContainsKey(rate.Base))
_graph[rate.Base] = new List<string>();
if (!_graph.ContainsKey(rate.Target))
_graph[rate.Target] = new List<string>();
_graph[rate.Base].Add(rate.Target);
_graph[rate.Target].Add(rate.Base);
}
}
}
Now traverse that graph using recursion:
public double Rate(string baseCode, string targetCode)
{
if (_graph[baseCode].Contains(targetCode)) {
// found the target code
return GetKnownRate(baseCode, targetCode);
}
else {
foreach (var code in _graph[baseCode]) {
// determine if code can be converted to targetCode
double rate = Rate(code, targetCode);
if (rate != 0) // if it can than combine with returned rate
return rate * GetKnownRate(baseCode, code);
}
}
return 0; // baseCode cannot be converted to the targetCode
}
public double GetKnownRate(string baseCode, string targetCode)
{
var rate = rates.SingleOrDefault(fr => fr.Base == baseCode && fr.Target == targetCode);
var rate_i rates.SingleOrDefault(fr => fr.Base == targetCode && fr.Target == baseCode));
if (rate == null)
return 1 / rate_i.Rate
return rate.Rate;
}
Disclaimer: This is untested. Further, I'm sure this isn't the most performant approach to solve the problem (O(n) I think), but I believe it will work. There are a number of things you could add to improve the performance (e.g. saving every new combined rate calculation would eventually turn this into an effective O(1))
Wouldn't it be simpler to just have a list of all conversions to a single currency and then use that for any conversion? So something like (with USD as the base currency):
var conversionsToUSD = new Dictionary<string, decimal>();
public decimal Rate ( string baseCode, string targetCode )
{
if ( targetCode == "USD" )
return conversionsToUSD[baseCode];
if ( baseCode == "USD" )
return 1 / conversionsToUSD[targetCode];
return conversionsToUSD[baseCode] / conversionsToUSD[targetCode]
}
Now, this assumes that algebra is perfectly communicative. I.e., if I convert to EUR->USD->GBP I'll get the same as converting from EUR->GBP. That might not actually be the case in reality in which case, you would need every supported permutation.
Interesting problem!
First off, stay clear from double / floating point arithmetic. The .NET Decimal type should be quite sufficient and provide better precision! Such improved precision may be particularly important given the fact that the calculation of derived Fx rates requires a chain of multiple operations.
Another remark is that it is probably off-limits to introduce a simpler/shorter list of Exchange rates, whereby the Target is always the same [real or fictitious] currency. I'm assuming here that we should use the listed rate when available.
So figuring out derived rates should become a [simplified] network solution, whereby
Given a Base and Target currencies, we identify all the shortest pathes (from Base to Target), given the authoritative (non derived) rates in the list. (We can hope that the shortest path would be 2, in all cases, but this may not be the case given very esoteric currencies).
for each of these shortest paths (I think it would be ludicrous to also consider longer pathes), we perform the simple arithmetic conversion, and...
hopefully confirm that these derived rates are all within a nominal margin of conversion error and therefore take the average of these rates
raise some alert... or just make a lot of money by using making a circular path and raking in the differential ;-)
I have no idea what that "double currency" is for... i'll just ignore it.
Attempt: List<List<FxRate>> res = Rates("EUR", "CHF"); yields {EUR-USD, USD-CHF}.
Looks promising! :)
public class FxRate
{
public string Base { get; set; }
public string Target { get; set; }
public double Rate { get; set; }
}
private List<FxRate> rates = new List<FxRate>
{
new FxRate {Base = "EUR", Target = "USD", Rate = 1.3668},
new FxRate {Base = "GBP", Target = "USD", Rate = 1.5039},
new FxRate {Base = "USD", Target = "CHF", Rate = 1.0694},
new FxRate {Base = "CHF", Target = "SEK", Rate = 8.12}
// ...
};
public List<List<FxRate>> Rates(string baseCode, string targetCode)
{
return Rates(baseCode, targetCode, rates.ToArray());
}
public List<List<FxRate>> Rates(string baseCode, string targetCode, FxRate[] toSee)
{
List<List<FxRate>> results = new List<List<FxRate>>();
List<FxRate> possible = toSee.Where(r => r.Base == baseCode).ToList();
List<FxRate> hits = possible.Where(p => p.Target == targetCode).ToList();
if (hits.Count > 0)
{
possible.RemoveAll(hits.Contains);
results.AddRange(hits.Select(hit => new List<FxRate> { hit }));
}
FxRate[] newToSee = toSee.Where( item => !possible.Contains(item)).ToArray();
foreach (FxRate posRate in possible)
{
List<List<FxRate>> otherConversions = Rates(posRate.Target, targetCode, newToSee);
FxRate rate = posRate;
otherConversions.ForEach(result => result.Insert(0, rate));
results.AddRange(otherConversions);
}
return results;
}
Comments?
PS: you can get the cheaper convertion with double minConvertion = res.Min(r => r.Sum(convertion => convertion.Rate));
The most straight-forward algorithm would probably just be like Dijkstra's shortest path or something on a graph you generate using that list. Being that you don't know beforehand how long the path will be, this isn't really a problem that can be elegantly solved by a LINQ query. (Not that it's not possible, it's just probably not what you should pursue.)
On the other hand, if you know that there is a path from any currency to any other, and that there is only one possible conversion between any two currencies on the list (ie, if USD > EUR and USD > CHF exist, then EUR > CHF doesn't exist or you can ignore it), you can simply generate something like a doubly linked list and traverse. Again though, this isn't something that can be elegantly solved through LINQ.
Generate all of them and cache them. Given initial set this function will generate all existing pairs (inside same list) without graphs or recursion, by simple expanding initial list as it iterates.
public static void CrossRates(List<FxRate> rates)
{
for (int i = 0; i < rates.Count; i++)
{
FxRate rate = rates[i];
for (int j = i + 1; j < rates.Count; j++)
{
FxRate rate2 = rates[j];
FxRate cross = CanCross(rate, rate2);
if (cross != null)
if (rates.FirstOrDefault(r => r.Ccy1.Equals(cross.Ccy1) && r.Ccy2.Equals(cross.Ccy2)) == null)
rates.Add(cross);
}
}
}
This utility function will generate individual cross rate.
public static FxRate CanCross(FxRate r1, FxRate r2)
{
FxRate nr = null;
if (r1.Ccy1.Equals(r2.Ccy1) && r1.Ccy2.Equals(r2.Ccy2) ||
r1.Ccy1.Equals(r2.Ccy2) && r1.Ccy2.Equals(r2.Ccy1)
) return null; // Same with same.
if (r1.Ccy1.Equals(r2.Ccy1))
{ // a/b / a/c = c/b
nr = new FxRate()
{
Ccy1 = r2.Ccy2,
Ccy2 = r1.Ccy2,
Rate = r1.Rate / r2.Rate
};
}
else if (r1.Ccy1.Equals(r2.Ccy2))
{
// a/b * c/a = c/b
nr = new FxRate()
{
Ccy1 = r2.Ccy1,
Ccy2 = r1.Ccy2,
Rate = r2.Rate * r1.Rate
};
}
else if (r1.Ccy2.Equals(r2.Ccy2))
{
// a/c / b/c = a/b
nr = new FxRate()
{
Ccy1 = r1.Ccy1,
Ccy2 = r2.Ccy1,
Rate = r1.Rate / r2.Rate
};
}
else if (r1.Ccy2.Equals(r2.Ccy1))
{
// a/c * c/b = a/b
nr = new FxRate()
{
Ccy1 = r1.Ccy1,
Ccy2 = r2.Ccy2,
Rate = r1.Rate * r2.Rate
};
}
return nr;
}