Search code examples
c#listsortingcriteriamin

Sorting points list based on a min coordinate criteria


I hope you can help me out on this one. I have to do some "special sorting" of a list of points (x,y,z coordinates) as a part of a larger code.

This list (by definition) will:

i) Always have a column with all the values equal zero.

ii) The first and the last point will always be the same.

The sorting of the list will depend on which column is equal to zero. I can identify this column myself with no problem (see code) but I am struggling when it comes with the sorting bit. First I have to find a the point that meet some specific criteria, then reorganise the list based on this. I have explained the sorting criteria as comments in the code (see sections 2 and 3).

If you could provide assistance on 2) and 3) that would be great (the first part is ok I think).

Many thanks

The code:

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{

[STAThread]

public static void Main(string[] args)
{
    //Populating the list
    var ListPoints = new List<double[]>();

    double[] P0 = { 10, 10, 0 };
    double[] P1 = { 10, 0, 0 };
    double[] P2 = { 0, 0, 0 };
    double[] P3 = { 0, 10, 0 };

    ListPoints.Add(P0);
    ListPoints.Add(P1);
    ListPoints.Add(P2);
    ListPoints.Add(P3);
    ListPoints.Add(P0);

    ///This list (by definition) will: 
    /// i) Always have a column with all the values equal zero
    /// ii) The first and the last point will always be the same. 
    ///We need to detect the column with all values = zero, because the list sorting will depend on this. 



    /// 1) Detect which columns has all values equal to zero using the columnZero variable
    var counterX = new List<int>();
    var counterY = new List<int>();
    var counterZ = new List<int>();


    for (int i = 0; i < ListPoints.Count - 1; i++)
    {
        //First column with all values equal zero
        if (ListPoints[i][0] == 0 && ListPoints[i][0] == ListPoints[i + 1][0]) { counterX.Add(1); }
        //Second column with all values equal zero
        if (ListPoints[i][1] == 0 && ListPoints[i][1] == ListPoints[i + 1][1]) { counterY.Add(1); }
        //Third column with all values equal zero
        if (ListPoints[i][2] == 0 && ListPoints[i][2] == ListPoints[i + 1][2]) { counterZ.Add(1); }
    }

    if (counterX.Count == ListPoints.Count - 1)
    { Console.WriteLine("all points of the 1st column are zero");}

    if (counterY.Count == ListPoints.Count - 1)
    { Console.WriteLine("all points of the 2nd column are zero");}

    if (counterZ.Count == ListPoints.Count - 1)
    { Console.WriteLine("all points of the 3rd column are zero");}

    /// 2) Now a point "Q" must be found in the list according to this:
    /// 2.1/ If the first column has all values = zero:
    ///      Find the row index of the smallest value in the second column.
    ///         If there are several rows in the second column with the same minimum value go and find between those which one has the smallest value in the third column.
    ///         If there is only one value in the second column keep that one.
    /// 2.2/ If the second column has all values = zero:
    ///      Find the row index of the smallest value in the first column.
    ///         If there are several rows in the first column with the same minimum value go and find between those which one has the smallest value in the third column.
    ///         If there is only one value in the first column keep that one.
    /// 2.3/ If the third column has all values = zero:
    ///      Find the row index of the smallest value in the first column.
    ///         If there are several rows in the first column with the same minimum value go and find between those which one has the smallest value in the second column.
    ///         If there is only one value in the first column keep that one.
    ///

    /// 3) Once this value has been found we have to put the list starting by this point "Q", then copy the previous values at the end of the list  and finally add again "Q". 
    ///    Example:The column with all values = 0  is column 3 and the generic point "Q" is the point "P2" in my list. The input is P0-P1-P2-P3-P0 but I want to have it P2-P3-P0-P1-P2.
}
}

Solution

  • Given your criteria, the first two points of your sorting algorithm degenerate into one much simpler algorithm.

    That is: No matter which column is full of 0's, you are always sorting by first column, then by second column, then by third column ascending values. This will leave your target item at the beginning of your list, and from there you just grab the correct order from the original list.

    private List<double[]> SpecialSort(List<double[]> list)
    {
      // Make an editable duplicate of your original list and remove the duplicated array at the start (or end) of the list.
      List<double[]> orig = new List<double[]>(list);
      orig.RemoveAt(0);
    
      // Copy and sort the list by 1st column, 2nd column, 3rd column.
      List<double[]> copy = orig.OrderBy(p => p[0]).ThenBy(p => p[1]).ThenBy(p => p[2]).ToList();
    
      // The first item in the copy-sorted list is your point "Q".
      // Find its index in the original list.
      int index = orig.IndexOf(copy[0]);
      List<double[]> sorted = new List<double[]>();
    
      // For the list count + 1 (adding point Q twice) add the original list
      // objects in the correct order, starting at "point'Q'".
      for (int i = 0; i <= orig.Count; i++)
      {
        sorted.Add(orig[(index + i) % orig.Count]);
      }
    
      return sorted;
    }
    

    Then just call as

    ListPoints = this.SpecialSort(ListPoints);