C# GH Why error happens in my components?

Hi everyone,
I’m new in scripting C# in GH.

I made component eliminating duplicate points.
It works well when I scripted in GH C# editor.
However, it occurs error when compiled by VisualStudio2017.

Does anyone know what is difference between GH C# Editor and VS2017?

Here attached is my .gh file contains both method, and here is my VS script.

elimduppoint.gh (12.6 KB)

Best,
Shimpei

protected override void SolveInstance(IGH_DataAccess DA)
_ {_
_ List pts = new List();_
_ List al = new List();_
_ DA.GetDataList(“pts”, pts);_

_ foreach (Point3d pt in pts)_
_ {_
_ if (!al.Contains(pt))_
_ {_
_ al.Add(pt);_
_ }_
_ }_

_ DA.SetData(“Unique”, al);_
_ }_

You need to use the generic version of List called List<T>. Type-safety is important.

protected override void SolveInstance(IGH_DataAccess DA)
{
  List<Point3d> points = new List<Point3d>();
  // Use parameter indices, not names to retrieve data if at all possible.
  if (!DA.GetDataList(0, points)) return; 

  // Always a good idea to initialize a list to an appropriate size.
  List<Point3d> filtered = new List<Point3d>(points.Count);

  // There are faster ways to find identical points, HashSet<Point3d> for one.
  // Also, you may want to add some tolerance checking rather than comparing
  // points exactly. 
  foreach (Point3d pt in points)
    if (!filtered.Contains(pt))
      filtered.Add(pt);

  DA.SetDataList(0, filtered);
}

If you’re getting warnings or errors, always post them. I cannot see your screen from here.

There are lots of differences, but only because the context within which the code executes is different. The language is the same.

Dear David,

Thank you for your answer!
Error is removed by scripting code you suggested.

I have one more question.
Componet by VS is faster than GH C# Editor?

Best,
Shimpei

It depends. Usually a little, but that is because the C# Scripts are compiled using a DEBUG flavour whereas you can choose to compile RELEASE on Visual Studio. Also there is less copying of data coming into the component, which can make a difference.

However given the code you posted, much bigger speed-ups can be gained by writing faster code. What you have there is a loop within a loop, meaning each additional point will take longer and longer to resolve. I think what you wrote is O(N^2). Using a better point searcher you can get it down to maybe O(log(N)).

Dear David,

I earned useful knowledge from you.
Thanks again!

I will focus on writing faster sode!

Best,
Shimpei

Specifically, the Contains() method on List<T> is an O(N) operation, because it compares the value against each and every element in the list, until it finds a match. This means that on a list twice as long it will take roughly twice as long to find a match, and exactly twice as long to determine there is no match.

The Contains() method on HashSet<T> on the other hand is O(1). It always takes the same amount of time, regardless of many items there already are in the set. The downside of HashSet<T> though is that it requires more memory and loses the order of points. So if you care about the ordering remaining intact, you will need to maintain both a list and a hashset.

A spatial subdivision of points such as for example an OcTree or a k-dTree will typically have O(log(N)) lookup, with the added benefit that you can specify a tolerance, so that points which are not exactly identical yet still very close together are still found as pairs. Sadly, the .NET framework does not have a standard collection type like this, but both RhinoCommon and Grasshopper do, to wit the Rhino.Geometry.RTree class and the Grasshopper.Kernel.Geometry.SpatialTrees.Node3d class.

1 Like