Sorry if the question is redundant, but I couldn't find a solution for my particular case.
Please consider this block of code:
public interface IPoint {}
public class GazePoint : IPoint {}
public Point AvgPoint(IEnumerable<IPoint> locations) {}
List<GazePoint> gazePoints = new List<GazePoint>();
//...
// this doesn't work:
Point avg = AvgPoint(gazePoints);
Could you please explain why it doesn't work (I was assuming C# 4.0 has solved this issue) and how can I change the signature of AvgPoint() method to make it possible to receive different implementations of IPoint. (I don't want to cast gazePoints collection to another type of collection, because it is in a big loop, and I'm concern about the performance.
[Update]: I had defined GazePoint as struct, and that was the source of problem. Still, I don't know why struct is not working here.
I'm not sure what the exact problem is you're having, but here's how it worked for me:
First, some actual class implementations:
public interface IPoint
{
int X { get; set; }
int Y { get; set; }
}
public class Point : IPoint
{
public int X { get; set; }
public int Y { get; set; }
public Point()
{
}
public Point(int x, int y)
{
X = x;
Y = y;
}
}
public class GazePoint : IPoint
{
public int X { get; set; }
public int Y { get; set; }
public GazePoint()
{
}
public GazePoint(int x, int y)
{
X = x;
Y = y;
}
}
Then an actual AvgPoint method implementation:
public static Point AvgPoint(IEnumerable<IPoint> locations)
{
if (locations == null || !locations.Any()) return new Point(0, 0);
return new Point((int) locations.Average(l => l.X),
(int) locations.Average(l => l.Y));
}
And finally a few tests:
public static void Main()
{
var points = new List<Point>
{
new Point(1, 2),
new Point(3, 4)
};
var gazePoints = new List<GazePoint>
{
new GazePoint(1, 2),
new GazePoint(3, 4)
};
Point avgPoint = AvgPoint(points);
Point avgGazePoint = AvgPoint(gazePoints);
Console.WriteLine("Average Point = {0}, {1}", avgPoint.X, avgPoint.Y);
Console.WriteLine("Average GazePoint = {0}, {1}", avgGazePoint.X, avgGazePoint.Y);
}
If your goal is to have the method return the average in the same type that was passed in, you can make it generic like so:
public static T AvgPoint<T>(IEnumerable<T> locations) where T : IPoint, new()
{
if (locations == null || !locations.Any()) return new T {X = 0, Y = 0};
return new T {X = (int) locations.Average(l => l.X),
Y = (int) locations.Average(l => l.Y)};
}
Related
How I can write make method Compare in RoomComparerByVolume ?
"Define a generic class RoomComparerByVolume<> implementing IComparer interface.
Impose a constraint on the type argument so that it should implement the IShape interface.
This comparer should perform comparison of rooms by room volume."
public interface IShape
{
public double Area()
{
return 0;
}
}
public class Rectangle : IShape
{
public double Length { get; set; }
public double Width { get; set; }
public double Area()
{
return Length * Width;
}
}
public class Trapezoid : IShape
{
public double Length1 { get; set; }
public double Length2 { get; set; }
public double Width { get; set; }
public double Area()
{
return (Length1 + Length2) * Width / 2;
}
}
public class Room<T> where T : IShape, ICloneable, IComparable
{
public double Height { get; set; }
public T Floor;
public double Volume()
{
return Height * Height;
}
public object Clone()
{
return new Room<T> { Height = this.Height, Floor = this.Floor };
}
public int CompareTo(object o)
{
Room<T> r = o as Room<T>;
if (r != null)
return this.Volume().CompareTo(r.Volume());
else
throw new Exception("Unable to compare");
}
}
public class RoomComparerByVolume<T> : IComparer<T> where T : IShape
{
}
Your question is a bit unclear. If compare "by room volume" means in fact compare Area() values
and you want to imeplement a corresponding comparer, you can put something like this
public sealed class ShapeComparerByArea<T> : IComparer<T> where T : IShape
{
public int Compare(T left, T right)
{
if (ReferenceEquals(left, right))
return 0;
if (left == null)
return 1;
if (right == null)
return -1;
return left.Area().CompareTo(right.Area());
}
}
If you want to define comparable Room class (which has Shape Floor) you can put it as
public class Room : IComparable<Room> {
public Room(IShape floor, double height) {
Floor = floor ?? throw new ArgumentNullException(nameof(floor));
Height = height > 0
? height
: throw new ArgumentOutOfRangeException(nameof(height));
}
public IShape Floor { get; }
public double Height { get; }
public double Volume => Floor.Area() * Height;
public int CompareTo(Room other) {
if (ReferenceEquals(this, other))
return 0;
if (other is null)
return 1;
return Volume.CompareTo(other.Volume);
}
}
Finally, RoomComparerByVolume can be
public sealed class RoomComparerByVolume : IComparer<Room> {
public int Compare(Room left, Room right) {
if (ReferenceEquals(left, right))
return 0;
if (left == null)
return 1;
if (right == null)
return -1;
return left.Volume.CompareTo(right.Volume);
}
}
Demo:
Room myRoom = new Room(
new Trapezoid() { Length1 = 5, Length2 = 7, Width = 3},
2.8);
Room myOtherRoom = new Room(
new Rectangle() { Length = 3, Width = 4 },
2.5);
Console.WriteLine(myRoom.CompareTo(myOtherRoom));
RoomComparerByVolume comparer = new RoomComparerByVolume();
Console.WriteLine(comparer.Compare(myRoom, myOtherRoom));
I would assume that the desired declaration should look like
public class RoomComparerByVolume<T> : IComparer<Room<T>> where T : IShape, ICloneable, IComparable{
public int Compare(Room<T> left, Room<T> right) {
...
}
That way you can compare the two rooms. But note that the two rooms need to be the same shape using this method. Also note that you need to use the same generic constraints as you are using for Room<T>.
Also note that in many cases you do not need to create a specific comparer type. Often you can use a delegate to do the actual comparison:
Comparer<Room<Trapezoid>>.Create((l, r) => l.Volume().CompareTo(r.Volume));
I have created IShallowCloneable interface to create shallow copy of class for All of my class but with inheritance it is not working properly.
Look at Main method, node2 is returning Point3D object Instead of Node.
Details
Point2D is Base Class
Point3D Class Derived from Point2D Class
Node
Class Derived from Point3D Class
using System;
namespace ConsoleAppTest
{
internal static class Program
{
private static void Main()
{
try
{
var node = new Node(1, 0, 0, 0);
var node2 = node.ShallowClone();//this code is returing Point3D Object instead of Node
}
catch (Exception)
{
throw;
}
finally
{
Console.ReadLine();
}
}
}
public interface IShallowCloneable<T>
{
T ShallowClone();
}
public class Point2D : IShallowCloneable<Point2D>
{
public int X { get; set; }
public int Y { get; set; }
public Point2D()
{
}
public Point2D(int x, int y)
{
X = x;
Y = y;
}
public Point2D ShallowClone()
{
return new Point2D(X, Y);
}
}
public class Point3D : Point2D, IShallowCloneable<Point3D>
{
public int Z { get; set; }
public Point3D()
{
}
public Point3D(int x, int y,int z):base(x,y)
{
Z = z;
}
new public Point3D ShallowClone()
{
return new Point3D(X, Y,Z);
}
}
public class Node:Point3D, IShallowCloneable<Node>
{
public int Id { get; set; }
public Node()
{
}
public Node(int id,int x, int y, int z):base(x,y,z)
{
Id = id;
}
Node IShallowCloneable<Node>.ShallowClone()
{
return new Node(Id,X, Y, Z);
}
}
}
Because for Node you've implemented IShallowCloneable<Node> as explicit interface, so it will work only if you cast to it:
// prints Node
Console.WriteLine(((IShallowCloneable<Node>)node).ShallowClone().GetType().Name);
If you want it to behave as Point3D you need to implement it as you do there ( hiding inherited Point2D implementation with new keyword).
so if you want to use ShallowClone method Explicitly without changing Class
var node = new Node(1, 0, 0, 0);
var node2 = ((IShallowCloneable<Node>)node).ShallowClone();
or if you want implicit implementation you have to Modify ShallowClone() method implementation in Node Class like this
new public Node ShallowClone()
{
return new Node(Id, X, Y, Z);
}
Additional Reference
C# Interfaces. Implicit implementation versus Explicit implementation
I have a class that I use to describe a XYZ coordinate along with 3 properties.
The class looks like this:
class dwePoint
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public string Prop3 { get; set; }
public override bool Equals(object obj)
{
return Equals(obj as dwePoint);
}
protected bool Equals(dwePoint other)
{ //This doesnt seem to work
if(Prop1== "Keep")
{
return false;
}
return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = X.GetHashCode();
hashCode = (hashCode * 397) ^ Y.GetHashCode();
hashCode = (hashCode * 397) ^ Prop1.GetHashCode();
hashCode = (hashCode * 397) ^ Z.GetHashCode();
return hashCode;
}
}
}
Checking the XYZ on the Equals, I can filter out duplicates only based on the actual coordinates, ignoring the properties.
In my code, I use a list, so I call the List.Distinct()
Now there is one thing I cant figure out yet:
It is possible there are 2 points with the same XYZ, but with different properties.
In that case I always want to keep the one with a specific string (for example "Keep") and always remove the one that has some other value.
I was already trying some if statements, without any luck...
How should I handle this ?
What you want is not really possible with Distinct since it uses your Equals as it's only input for equality (as it should), so it has no way to even be aware that there could be a difference between the objects.
I think it would be a better design for you to compose your class using a new class, e.g. Point3D containing your coordinates and your 3 properties. Then you can group by the point, and for everything that has more than one equal point, apply your own logic as to which to keep.
In code:
class Point3D
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
// Equals and get hash code here
}
class dwePoint
{
Point3D Coordinate {get;}
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public string Prop3 { get; set; }
}
// Filter list by applying grouping and your custom logic
points = points.GroupBy(p => p.Coordinate)
.Select(x =>
x.OrderByDescending(p => p.Prop1 == "Keep") // Sort so the element you want to keep is first
.First() // If there is only one element, the ordering will not matter
).ToList();
If you really want, the GroupBy also works with your current class design, since only the coordinates takes part in the Equals.
Your GetHashCode runs into a nullref if Prop1 == null, you should fix that.
And another solution: use Aggregate and Lamda to distinct your list. The Equal() on your class only compares the X,Y and Z - the Aggregate lambda makes sure you keep what you want. Probably put the Aggregate in a extension method or Function.
static void Main()
{
List<dwePoint> points = new List<dwePoint>();
// Testdata
for (int x = 0; x < 3; x++)
for (int y = 0; y < 3; y++)
for (int z = 0; z < 3; z++)
{
points.Add(new dwePoint { X = x, Y = y, Z = z });
if (x == y && x == z) // and some duplicates to Keep
points.Add(new dwePoint { X = x, Y = y, Z = z, Prop1 = "Keep" });
}
// prefer the ones with "Keep" in Prop1
var distincts = points.Aggregate(new HashSet<dwePoint>(), (acc, p) =>
{
if (acc.Contains(p))
{
var oldP = acc.First(point => point.X == p.X && point.Y == p.Y && point.Z == p.Z);
if (oldP.Prop1 == "Keep")
{
// do nothing - error, second point with "keep"
}
else
{
acc.Remove(oldP);
acc.Add(p); // to use this ones other props later on ....
}
}
else
acc.Add(p);
return acc;
}).ToList();
Console.WriteLine(string.Join(" - ", points));
Console.WriteLine(string.Join(" - ", distincts));
Console.ReadLine();
}
private class dwePoint
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public string Prop3 { get; set; }
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
public override bool Equals(object obj)
{
return Equals(obj as dwePoint);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = X.GetHashCode();
hashCode = (hashCode * 397) ^ Y.GetHashCode();
hashCode = (hashCode * 397) ^ Z.GetHashCode();
return hashCode;
}
}
public override string ToString() => $"{X}-{Y}-{Z}-{Prop1}-{Prop2}-{Prop3}";
protected bool Equals(dwePoint other)
{
return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z);
}
}
I had the same answer in mind as driis provided..
But, I would like to provide you with another option.
You can write a Distinct on your own as an extension method.
Here is a work around. I wrote a sample code, so that you can understand better.
static class Program
{
static void Main(string[] args)
{
List<Abc> list = new List<Abc>()
{
new Abc()
{
a = 5,
b = 6,
s = "Phew"
},
new Abc()
{
a = 9,
b = 10,
s = "Phew"
},
new Abc()
{
a = 5,
b = 6,
s = "Keep"
},
new Abc()
{
a = 9,
b = 10,
s = "Keep"
},
new Abc()
{
a = 5,
b = 6,
s = "Phew"
},
new Abc()
{
a = 9,
b = 10,
s = "Phew"
},
};
list = list.MyDistinct();
}
// Extension Method
public static List<Abc> MyDistinct(this List<Abc> list)
{
List<Abc> newList = new List<Abc>();
foreach (Abc item in list)
{
Abc found = newList.FirstOrDefault(x => x.Equals(item));
if (found == null)
{
newList.Add(item);
}
else
{
if (found.s != "Keep" && item.s == "Keep")
{
newList.Remove(found);
newList.Add(item);
}
}
}
return newList;
}
}
class Abc
{
public int a, b;
public string s;
public override bool Equals(object obj)
{
Abc other = obj as Abc;
return a == other.a && b == other.b;
}
public override int GetHashCode()
{
return a.GetHashCode() ^ b.GetHashCode();
}
}
Hope it will help you..
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I want to create object "A" which will have x, y parameters.
and A must be an array. What's best practice of declaring and constructing such object ? for example something like this:
A[0].x=5
A[0].y=3
A[1].x=6
A[1].y=4
Update
I've done this way:
public class PersonalWaypoints
{
public float x { get; set; }
public float y { get; set; }
}
public class MainClass:MonoBehaviour
{
then in void Start() {
PersonalWaypoints[] pw = new PersonalWaypoints[waypoints.Length];
pw[0].x = waypoints[0].transform.position.x ;
pw[0].y = waypoints[0].transform.position.y ;
but then I cannot use pw in Update() { because it doesn't exist in current context.
And to have it in context I cannot move PersonalWaypoints[] pw = new PersonalWaypoints[waypoints.Length]; to class definition because waypoints.Length is unknown while defining class.
You question is a bit vague, if you want autoexpanding array-like collection you have to have two objects: one for point
//TODO: think over, may be you want a struct, not class
// May be you want just a standard Point struct
public class Item {
public int x {get; set;}
public int y {get; set;}
}
and one for "array" (which is an indexer in fact)
//TODO: you may want to implement IEnumerable<Item>
public class MyClass {
private List<Item> m_Items = new List<Item>();
private void Expand(int index) {
if (index < 0)
throw new ArgumentOutOfRangeException("index");
for (int i = m_Items.Count; i <= index; ++i)
m_Items.Add(new Item());
}
// indexer: mimics auto expanding array
public Item this[int index] {
get {
Expand(index);
return m_Items[index];
}
}
public int Count {
get {
return m_Items.Count;
}
}
}
...
MyClass test = new MyClass();
// test will be expanded to have 1 item: test[0]
test[0].y = 456;
// test will be expanded to have 6 items [0..5]
test[5].x = 123;
Define a Point type which has your fields:
public class Point
{
public int X { get; set; }
public int Y { get; set; }
}
Then create an array of Points (or a List<Point>):
var A = new[] {
new Point { X = 5, Y = 3 },
new Point { X = 6, Y = 4 }
};
You can, of course, get there from values for x and y which are not hard-coded into the object creation. For example, say that you have a list xs with integers that should be the x coordinates, and a simliar (and of equal length!) list ys wity y-values. Then, you'll get a list of Points from
var points = xs.Zip(ys, (x,y) => new Point { X = x, Y = y });
Then access the coordinates just the way you wanted: points[1].x is the x-coordinate of the second point.
You can create a class with your parameters for it and then create an Array or List of the class:
public class _A
{
public int x;
public int y;
}
_A[] A;
Or
List<_A> = new List<_A>();
public class A
{
int x;
int y;
}
A[] numbers = new A[10];
sealed class A {
readonly int m_x;
readonly int m_y;
internal A(int x, int y) {
m_x = x;
m_y = y;
}
internal int X {
get {
return m_x;
}
}
internal int Y {
get {
return m_y;
}
}
}
And then to get array of objects:
var myVar = new A[1]; // Array size between []
First you must make a class Coordinate
class Coordinate{
public int x;
public int y;
public Coordinate(int x, int y){
this.x=x;
this.y=y;
}
After that you create an array of Coordinates
Coordinate[]A=new Coordinate[10];
A[0]=new Coordinate(0,0);
A[1]=new Coordinate(5,4);
Sorry for the title i will put here an example of what i want to accomplish:
namespace mdclass
{
class pClass
{
static void Main()
{
tiles<int> tl = new tiles<int>();
tl[0].X = 0;
}
}
class tiles<T> : List<T>
{
public int X
{
//get/set the X-coordonate
}
public int Y
{
//get/set the Y-coordonate
}
}
}
how can i transfer the [0] from the tl[0] in the public int X and work with it?
Create a class for x and y coordinates:
public sealed class Point {
public int X { get; set; }
public int Y { get; set; }
}
Use the Point class to store the coordinates into the list:
public sealed class Program {
public static void Main() {
var tiles = new List<Point>();
tiles.Add(new Point { X = 5, Y = 10 });
tiles[0].X = 15;
}
}
Could you not just make tl public?
Then myInt = mypClass.tl[0].X
A data heirachy like this might work for you (no time to add actual code, sorry!). Then you could implement appropriate getters and setters.
Public class Grid {
List<Row>
}
Public class Row{
List<Point>
}
Public Class Point{
public int X { get; set; }
public int Y { get; set; }
}