Sorting ArrayList of shapes - c#

I have an ArrayList of MCommand objects (cmdList) and I want to sort it so that shapes with closest points are next to each other in the ArrayList. For example, say I have three lines in the ArrayList:
line(xs, ys, zs, xe, ye, ze)
cmdList[0] = line1(1.3, 2.5, 3, 4, 5, 6)
cmdList[1] = line2(1, 5, 6.77, 7, 8, 2)
cmdList[2] = line3(1, 6, 3, 1, 1.1, 1)
Points that need to be close are LastPosition of line with BeginPosition of other line.
LastPosition of line is (xe, ye, ze) and BeginPosition of line is (xs, ys, zs).
I now do my sorting by executing a built in sorting:
cmdList.Sort(new MCommandComparer());
This is how my MCommand looks like and how i calculate distance of two points:
public abstract class MCommand
{
//...
public abstract Point3 LastPosition { get; }
public abstract Point3 BeginPosition { get; }
public double CompareTo(Object obj)
{
Point3 p1, p2;
p1 = this.BeginPosition;
p2 = ((MCommand)obj).LastPosition;
return Math.Sqrt(Math.Pow((p2.x - p1.x), 2) +
Math.Pow((p2.y - p1.y), 2) +
Math.Pow((p2.z - p1.z), 2));
}
}
This is the comparer i use:
public class MCommandComparer : IComparer
{
private MCommand prev;
double distanceFromPrev = 0;
double distanceFromCurr = 0;
public int Compare(object o1, object o2)
{
if ((MCommand)o2 == prev)
return 0;
if (prev != null)
distanceFromPrev = ((MCommand)o1).CompareTo(prev);
distanceFromCurr = ((MCommand)o1).CompareTo(o2);
prev = (MCommand)o2;
return (int)(distanceFromCurr - distanceFromPrev);
}
}
I've tried many ways and got lost... This doesnt sort shapes the way I want to. My question is, what I could be doing wrong? Should i try writing sorting from scratch? My ArrayList can contain couple thousands elements, and i need to have an efficient sort.

What could I be doing wrong?
You're assuming the elements will be presented to you in a particular order - you're remembering the "previous" element, which is a huge red flag.
The way various sorts work won't do this at all. Basically your comparer should be stateless. It sounds like you don't really have a total ordering here - there's no way of taking any two arbitrary elements and saying which should be before or after the other one.
I don't know exactly how you'd do whatever you need, but I don't think the standard sorting built into .NET is going to help you much.

You could make your MCommand class subscribe to IComparable. In doing this you would allow your list to sort your shapes without the need for additional Comparer Object. All the sorting functionality would be handled by the list and the objects within it.

Related

Read coordinates from txt file in Unity3D

i've just started to learn unity and i'm having some troubles to go ahead with my exercises.
I need to move 2 cars using coordinates stored in a .txt file called "positions.txt".
The cars have to move at the same time.
Inside the "cartesian" list there are numbers which have to be splitted in groups of 4 (time, x, y, z).
I'd like to create 2 arrays for each car: a time array and a Vector3 array.
First of all, i need to read the file and store the numbers in the arrays. I found several options and i tried this one without success: https://allison-liem.medium.com/unity-reading-external-json-files-878ed0978977
Which approach should i follow?
Thank you.
File "positions.txt"
[
{
"id":"car_1",
"position":{
"cartesian":[
1,0,0,0,
2,0,0,2,
3,1,0,3,
4,1,0,6,
5,2,1,9,
6,2,0,11,
7,3,1,13,
8,3,0,15,
9,3,1,18,
10,4,1,20]
}
},
{
"id":"car_2",
"position":{
"cartesian":[
1,0,0,0,
2,0,0,2,
3,1,0,3,
4,1,0,6,
5,2,1,9,
6,2,0,11,
7,3,1,13,
8,3,0,15,
9,3,1,18,
10,4,1,20]
}
}
]
So first of all you have a JSON so see Serialize and Deserialize Json and Json Array in Unity
I would recommend the Newtonsoft Json.NET package and do e.g.
[Serializable]
public class Position
{
// you can also go for array if you liked
// in JSON it is the same
public List<int> cartesian;
}
[Serializable]
public class Car
{
public string id;
public Position position;
}
and then
var json = File.RealAllText(FILEPATH);
// again could also go for array here
List<Car> cars = JsonConvert.DeserializeObject<List<Car>>(json);
However, the cartesian arrays are a bit "stupid" - have in mind that once this is handled as a list/array there are no line breaks and no good meaning for your redundant indices (1, 2, 3, 4, ...) at the beginning of each set.
I'd like to create 2 arrays for each car: a time array and a Vector3 array.
his wouldn't make sense in my eyes - if something that information clearly belongs coupled together so splitting it into individual arrays would be bad.
Either way you will have to manually extract your values when iterating over the list/array
Go in sets of 4 items
Ignore the first - it seems to be a redundant index
take the last three items and fill them into x,y,z of a vector
like e.g.
[Serializable]
public class Position
{
// you can also go for array if you liked
// in JSON it is the same
public List<int> cartesian;
public List<Vector3> GetPositions()
{
var count = cartesian.Count / 4;
var result = new List<Vector3>(count);
for(var resultIndex = 0; resultIndex < count; resultIndex++)
{
var cartesianIndex = resultIndex * 4;
var position = new Vector3(cartesian[cartesianIndex + 1], cartesian[cartesianIndex + 2], cartesian[cartesianIndex + 3]);
result.Add(position);
}
}
}
or if you actually need also that first value I would use a custom type like e.g.
public readonly struct TimeFrame
{
public int Time { get; }
public Vector3 Position { get; }
public TimeFrame(int time, Vector position)
{
Time = time;
Position = position;
}
}
and then adjust accordingly
[Serializable]
public class Position
{
// you can also go for array if you liked
// in JSON it is the same
public List<int> cartesian;
public List<TimeFrame> GetPositions()
{
var count = cartesian.Count / 4;
var result = new List<TimeFrame>(count);
for(var resultIndex = 0; resultIndex < count; resultIndex++)
{
var cartesianIndex = resultIndex * 4;
var time = cartesian[cartesianIndex];
var position = new Vector3(cartesian[cartesianIndex + 1], cartesian[cartesianIndex + 2], cartesian[cartesianIndex + 3]);
result.Add(new TimeFrame(time, position));
}
}
}
I saw that the medium article you're referring to uses Unity's built in JSON parsing library which does not support array parsing, as pointed out by this answer here https://stackoverflow.com/a/36244111/13489126.
That is the reason why your approach was not working.
I would recommend you to use Newtonsoft Json Parser instead of Unity's.

OrderBy with a non-transitive IComparer

Take a custom IComparer, that treats two doubles as equal if their difference is less than a given epsilon.
What would happen if this IComparer is used in a OrderBy().ThenBy() clause?
Specifically I am thinking of the following implementation:
public class EpsilonComparer : IComparer<double>
{
private readonly double epsilon;
public EpsilonComparer(double epsilon)
{
this.epsilon = epsilon;
}
public int Compare(double d1, double d2)
{
if (Math.Abs(d1-d2)<=epsilon) return 0;
return d1.CompareTo(d2);
}
}
Now this IComparer relationship is clearly not transitive. (if a ~ b and b ~ c then a ~ c)
With epsilon== 0.6 :
Compare(1, 1.5) == 0
Compare(1.5, 2) == 0
yet
Compare(1, 2 ) == -1
What would happen if this IComparer was used in an OrderBy query, like this:
List<Item> itemlist;
itemList = itemlist.OrderBy(item=>item.X, new EpsilonComparer(0.352))
.ThenBy (item=>item.Y, new EpsilonComparer(1.743)).ToList();
Would the sort behave as one would expect, sorting the list first by X, then by Y, while treating roughly equal values as exactly equal?
Would it blow up under certain circumstances?
Or is this whole sort ill-defined?
What exactly are the consequences of using an IComparer without transitivity?
(I know that this is most likely undefined behavior of the c# language. I am still very much interested in an answer.)
And is there an alternative way to get this sorting behaviour?
(besides rounding the values, which would introduce artifacts when for two close doubles one is rounded up and the other down)
An online fidle of the code in this question is available here:
The problem is that the first sorting level (on X) can result in different orders already. Imagine that all items are within one epsilon of each other. Then all sort orders are consistent with your comparer because it will always return 0. The sort algorithm could flip coins and still provide a "right" answer. Not useful.
If the first level is arbitrarily sorted, you cannot expect the 2nd sorting level to work.
Of course, all of this discussion is moot because you are violating the precondition of the sorting API. Even if it happened to work, you couldn't be sure that it would work on a) all data b) on all future releases of .NET.
How can you still achieve your goal? Your problem is just ill-defined because many solutions are possible. I get what you want to achieve but it is not possible with your current definition of the problem.
I propose this: sort all items by X (without epsilon). Then, traverse the sorted items left-to-right and merge the items into groups that one epsilon wide at most. That gives you groups of items whose X-value is at most epsilon apart.
You can then use the group number as the first sorting level. It is just a simple integer, so no trouble sorting on it. For the Y field, you can then use a normal comparer without epsilon (or repeat the same trick).
view my code snippet here. it's just for first level sorting and not optimized.
OrderBy and ThenBy are using general algorithm. you need to re-implement OrderBy and ThenBy with special algorithm like mine. then it can work as OrderBy().ThenBy().
Detail of algorithm:
in a sorted sequence(x1 x2 x3...) under your EpsilonComparer, if x4>x1, then x5>x1. if x4=x1, then x3=x1 and either x5>x1 or x5=x1.
with epsilon(0.4), input following numbers:0.1, 0.6, 1, 1.1, 1.6, 2, 2, 2.6, 3, 3.1, 3.6, 4, 4.1, 4.6, 5, 5.1, 5.6, 6, 6.1, 6.6
result:0.1 0.6 1 1.1 (1.6 2 2 ) 2.6 3 3.1 3.6 4 4.1 4.6 (5 5.1 ) 5.6 (6 6.1 ) 6.6
(a,b,c) indicates these numbers are equal and the order of numbers is not fixed. they can be (a,b,c), (c,a,b) and any other order.
a b indicates a < b and order is fixed.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Rextester
{
class Program
{
public static void Main(string[] args)
{
new EpsilonSort(new EpsilonComparer(0.4), 0.1, 0.6, 1, 1.1, 1.6, 2, 2, 2.6, 3, 3.1, 3.6, 4, 4.1, 4.6, 5, 5.1, 5.6, 6, 6.1, 6.6).Sort();
}
}
public class EpsilonSort
{
private readonly IComparer<double> m_comparer;
private readonly double[] m_nums;
public EpsilonSort(IComparer<double> comparer, params double[] nums)
{
this.m_comparer = comparer;
this.m_nums = nums;
}
public void Sort()
{
Node root = new Node();
root.Datas = new List<double>(this.m_nums);
foreach (double i in (double[])this.m_nums.Clone())
{
this.ProcessNode(i, root);
}
this.OutputNodes(root);
}
private void OutputNodes(Node root)
{
if (root.Datas == null)
{
foreach (var i in root.Nodes)
{
this.OutputNodes(i);
}
}
else
{
if (root.Datas.Count == 1)
{
Console.WriteLine(root.Datas[0]);
}
else
{
Console.Write('(');
foreach (var i in root.Datas)
{
Console.Write(i);
Console.Write(' ');
}
Console.WriteLine(')');
}
}
}
private void ProcessNode(double value, Node one)
{
if (one.Datas == null)
{
foreach (var i in one.Nodes)
{
this.ProcessNode(value, i);
}
}
else
{
Node[] childrennodes = new Node[3];
foreach (var i in one.Datas)
{
int direction = this.m_comparer.Compare(i, value);
if (direction == 0)
{
this.AddData(ref childrennodes[1], i);
}
else
{
if (direction < 0)
{
this.AddData(ref childrennodes[0], i);
}
else
{
this.AddData(ref childrennodes[2], i);
}
}
}
childrennodes = childrennodes.Where(x => x != null).ToArray();
if (childrennodes.Length >= 2)
{
one.Datas = null;
one.Nodes = childrennodes;
}
}
}
private void AddData(ref Node node, double value)
{
node = node ?? new Node();
node.Datas = node.Datas ?? new List<double>();
node.Datas.Add(value);
}
private class Node
{
public Node[] Nodes;
public List<double> Datas;
}
}
public class EpsilonComparer : IComparer<double>
{
private readonly double epsilon;
public EpsilonComparer(double epsilon)
{
this.epsilon = epsilon;
}
public int Compare(double d1, double d2)
{
if (Math.Abs(d1 - d2) <= epsilon) return 0;
return d1.CompareTo(d2);
}
}
}

How to stop enum from going out of bounds?

I'm still learning the ropes with C# programming. I am trying to write an application to solve Knight's Tour but have run into some grief when trying to get possible future positions for the knight.
For positions I am using a very simple struct:
public struct Position
{
public enum BoardRank { A = 1, B, C, D, E, F, G, H };
public BoardRank X;
public int Y;
}
In the knight class, my PossibleMoves() method begins like this:
public List<Position> PossibleMoves(Position position)
{
List<Position> positions = new List<Position>();
int[] multiply = new int[]{1, -1};
foreach (int times in multiply)
{
try{
Position possible = new Position();
possible.X = position.X + (Behaviour.X * times);
possible.Y = position.Y + (Behaviour.Y * times);
positions.Add(possible);
}
...
For position = A1 and times = -1, you can see how Behaviour.X could quickly fall out of bounds, but I assumed this would have been picked up by the try block.
I tried adding a {get; set;} on the enum declaration but that threw some useless syntax errors in VS2010.
Is there anything else I can try here to stop my enum from going out of bounds?
I assumed this would have been picked up by the try block.
Nope. Enums in C# are "named numbers" effectively. They're not a complete set of values for the type.
Is there anything else I can try here to stop my enum from going out of bounds?
You can use Enum.IsDefined to check whether a value exists in the original enum. I would personally stop using public fields, and instead make Position immutable - then validate the value in the constructor. You could also have methods such as WithX which returned a new value based on the current value with just X changing. While you've got public fields, you're never going to be able to trust that any particular value is valid though.
It may be useful to use modulo to keep the values within a specific range:
possible.X = (position.X + (Behaviour.X * times)) % ((int)BoardRank.H + 1);
This way I am not sure whether an enum is the best solution here, as we're working with integers anyway. The numbers must be a sequence with no gaps and you have to make sure you take the highest defined enum value plus one. Thus, if you add a I to your enum, you need to change the modul.
Here I have a very simple program to illustrate how it works:
enum Foo { A, B, C }
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i % ((int)Foo.C + 1));
}
}
As you see we take i modulo C + 1 which makes C's integer value the actual range maximum. This is the output:
0, 1, 2, 0, 1, 2, 0, 1, 2, 0

C#: Loop to find minima of function

I currently have this function:
public double Max(double[] x, double[] y)
{
//Get min and max of x array as integer
int xMin = Convert.ToInt32(x.Min());
int xMax = Convert.ToInt32(x.Max());
// Generate a list of x values for input to Lagrange
double i = 2;
double xOld = Lagrange(xMin,x,y);
double xNew = xMax;
do
{
xOld = xNew;
xNew = Lagrange(i,x,y);
i = i + 0.01;
} while (xOld > xNew);
return i;
}
This will find the minimum value on a curve with decreasing slope...however, given this curve, I need to find three minima.
How can I find the three minima and output them as an array or individual variables? This curve is just an example--it could be inverted--regardless, I need to find multiple variables. So once the first min is found it needs to know how to get over the point of inflection and find the next... :/
*The Lagrange function can be found here.** For all practical purposes, the Lagrange function will give me f(x) when I input x...visually, it means the curve supplied by wolfram alpha.
*The math-side of this conundrum can be found here.**
Possible solution?
Generate an array of input, say x[1,1.1,1.2,1.3,1.4...], get an array back from the Lagrange function. Then find the three lowest values of this function? Then get the keys corresponding to the values? How would I do this?
It's been a while since I've taken a numerical methods class, so bear with me. In short there are a number of ways to search for the root(s) of a function, and depending on what your your function is (continuous? differentiable?), you need to choose one that is appropriate.
For your problem, I'd probably start by trying to use Newton's Method to find the roots of the second degree Lagrange polynomial for your function. I haven't tested out this library, but there is a C# based numerical methods package on CodePlex that implements Newton's Method that is open source. If you wanted to dig through the code you could.
The majority of root finding methods have cousins in the broader CS topic of 'search'. If you want a really quick and dirty approach, or you have a very large search space, consider something like Simulated Annealing. Finding all of your minima isn't guaranteed but it's fast and easy to code.
Assuming you're just trying to "brute force" calculate this to a certain level of prcision, you need your algorithm to basically find any value where both neighbors are greater than the current value of your loop.
To simplify this, let's just say you have an array of numbers, and you want to find the indices of the three local minima. Here's a simple algorithm to do it:
public void Test()
{
var ys = new[] { 1, 2, 3, 4, 5, 4, 3, 2, 1, 2, 3, 4, 5, 4, 3, 4, 5, 4 };
var indices = GetMinIndices(ys);
}
public List<int> GetMinIndices(int[] ys)
{
var minIndices = new List<int>();
for (var index = 1; index < ys.Length; index++)
{
var currentY = ys[index];
var previousY = ys[index - 1];
if (index < ys.Length - 1)
{
var neytY = ys[index + 1];
if (previousY > currentY && neytY > currentY) // neighbors are greater
minIndices.Add(index); // add the index to the list
}
else // we're at the last index
{
if (previousY > currentY) // previous is greater
minIndices.Add(index);
}
}
return minIndices;
}
So, basically, you pass in your array of function results (ys) that you calculated for an array of inputs (xs) (not shown). What you get back from this function is the minimum indices. So, in this example, you get back 8, 14, and 17.

C# Collection - Order by an element (Rotate)

I have an IEnumerable<Point> collection. Lets say it contains 5 points (in reality it is more like 2000)
I want to order this collection so that a specifc point in the collection becomes the first element, so it's basically chopping a collection at a specific point and rejoining them together.
So my list of 5 points:
{0,0}, {10,0}, {10,10}, {5,5}, {0,10}
Reordered with respect to element at index 3 would become:
{5,5}, {0,10}, {0,0}, {10,0}, {10,10}
What is the most computationally efficient way of resolving this problem, or is there an inbuilt method that already exists... If so I can't seem to find one!
var list = new[] { 1, 2, 3, 4, 5 };
var rotated = list.Skip(3).Concat(list.Take(3));
// rotated is now {4, 5, 1, 2, 3}
A simple array copy is O(n) in this case, which should be good enough for almost all real-world purposes. However, I will grant you that in certain cases - if this is a part deep inside a multi-level algorithm - this may be relevant. Also, do you simply need to iterate through this collection in an ordered fashion or create a copy?
Linked lists are very easy to reorganize like this, although accessing random elements will be more costly. Overall, the computational efficiency will also depend on how exactly you access this collection of items (and also, what sort of items they are - value types or reference types?).
The standard .NET linked list does not seem to support such manual manipulation but in general, if you have a linked list, you can easily move around sections of the list in the way you describe, just by assigning new "next" and "previous" pointers to the endpoints.
The collection library available here supports this functionality: http://www.itu.dk/research/c5/.
Specifically, you are looking for LinkedList<T>.Slide() the method which you can use on the object returned by LinkedList<T>.View().
Version without enumerating list two times, but higher memory consumption because of the T[]:
public static IEnumerable<T> Rotate<T>(IEnumerable<T> source, int count)
{
int i = 0;
T[] temp = new T[count];
foreach (var item in source)
{
if (i < count)
{
temp[i] = item;
}
else
{
yield return item;
}
i++;
}
foreach (var item in temp)
{
yield return item;
}
}
[Test]
public void TestRotate()
{
var list = new[] { 1, 2, 3, 4, 5 };
var rotated = Rotate(list, 3);
Assert.That(rotated, Is.EqualTo(new[] { 4, 5, 1, 2, 3 }));
}
Note: Add argument checks.
Another alternative to the Linq method shown by ulrichb would be to use the Queue Class (a fifo collection) dequeue to your index, and enqueue the ones you have taken out.
The naive implementation using linq would be:
IEnumerable x = new[] { 1, 2, 3, 4 };
var tail = x.TakeWhile(i => i != 3);
var head = x.SkipWhile(i => i != 3);
var combined = head.Concat(tail); // is now 3, 4, 1, 2
What happens here is that you perform twice the comparisons needed to get to your first element in the combined sequence.
The solution is readable and compact but not very efficient.
The solutions described by the other contributors may be more efficient since they use special data structures as arrays or lists.
You can write a user defined extension of List that does the rotation by using List.Reverse(). I took the basic idea from the C++ Standard Template Library which basically uses Reverse in three steps: Reverse(first, mid) Reverse(mid, last) Reverse(first, last)
As far as I know, this is the most efficient and fastest way. I tested with 1 billion elements and the rotation Rotate(0, 50000, 800000) takes 0.00097 seconds. (By the way: adding 1 billion ints to the List already takes 7.3 seconds)
Here's the extension you can use:
public static class Extensions
{
public static void Rotate(this List<int> me, int first, int mid, int last)
{
//indexes are zero based!
if (first >= mid || mid >= lastIndex)
return;
me.Reverse(first, mid - first + 1);
me.Reverse(mid + 1, last - mid);
me.Reverse(first, last - first + 1);
}
}
The usage is like:
static void Main(string[] args)
{
List<int> iList = new List<int>{0,1,2,3,4,5};
Console.WriteLine("Before rotate:");
foreach (var item in iList)
{
Console.Write(item + " ");
}
Console.WriteLine();
int firstIndex = 0, midIndex = 2, lastIndex = 4;
iList.Rotate(firstIndex, midIndex, lastIndex);
Console.WriteLine($"After rotate {firstIndex}, {midIndex}, {lastIndex}:");
foreach (var item in iList)
{
Console.Write(item + " ");
}
Console.ReadKey();
}

Categories